summaryrefslogtreecommitdiffstats
path: root/rust/src/api_wrappers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/api_wrappers.rs')
-rw-r--r--rust/src/api_wrappers.rs414
1 files changed, 414 insertions, 0 deletions
diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs
new file mode 100644
index 00000000..8651252c
--- /dev/null
+++ b/rust/src/api_wrappers.rs
@@ -0,0 +1,414 @@
+//! API endpoint handlers
+
+use errors::*;
+use api_server::Server;
+use fatcat_api::models;
+use fatcat_api::models::*;
+use fatcat_api::*;
+use futures::{self, Future};
+
+/// Helper for generating wrappers (which return "Box::new(futures::done(Ok(BLAH)))" like the
+/// codegen fatcat-api code wants) that call through to actual helpers (which have simple Result<>
+/// return types)
+macro_rules! wrap_entity_handlers {
+ // Would much rather just have entity ident, then generate the other fields from that, but Rust
+ // stable doesn't have a mechanism to "concat" or generate new identifiers in macros, at least
+ // in the context of defining new functions.
+ // The only stable approach I know of would be: https://github.com/dtolnay/mashup
+ ($get_fn:ident, $get_handler:ident, $get_resp:ident, $post_fn:ident, $post_handler:ident,
+ $post_resp:ident, $post_batch_fn:ident, $post_batch_handler:ident,
+ $post_batch_resp:ident, $get_history_fn:ident, $get_history_handler:ident,
+ $get_history_resp:ident, $model:ident) => {
+
+ fn $get_fn(
+ &self,
+ id: String,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
+ let ret = match self.$get_handler(id.clone()) {
+ Ok(entity) =>
+ $get_resp::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $get_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $post_fn(
+ &self,
+ entity: models::$model,
+ _context: &Context,
+ ) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> {
+ let ret = match self.$post_handler(entity, None) {
+ Ok(edit) =>
+ $post_resp::CreatedEntity(edit),
+ Err(Error(ErrorKind::Diesel(e), _)) =>
+ $post_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $post_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $post_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $post_batch_fn(
+ &self,
+ entity_list: &Vec<models::$model>,
+ _context: &Context,
+ ) -> Box<Future<Item = $post_batch_resp, Error = ApiError> + Send> {
+ let ret = match self.$post_batch_handler(entity_list) {
+ Ok(edit) =>
+ $post_batch_resp::CreatedEntities(edit),
+ Err(Error(ErrorKind::Diesel(e), _)) =>
+ $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $post_batch_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $get_history_fn(
+ &self,
+ id: String,
+ limit: Option<i64>,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_history_resp, Error = ApiError> + Send> {
+ let ret = match self.$get_history_handler(id.clone(), limit) {
+ Ok(history) =>
+ $get_history_resp::FoundEntityHistory(history),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_history_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $get_history_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_history_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+ }
+}
+
+macro_rules! wrap_lookup_handler {
+ ($get_fn:ident, $get_handler:ident, $get_resp:ident, $idname:ident, $idtype:ident) => {
+ fn $get_fn(
+ &self,
+ $idname: $idtype,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
+ let ret = match self.$get_handler($idname.clone()) {
+ Ok(entity) =>
+ $get_resp::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_resp::NotFound(ErrorResponse { message: format!("Not found: {}", $idname) }),
+ Err(e) => {
+ error!("{}", e);
+ $get_resp::BadRequest(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+ }
+}
+
+impl Api for Server {
+ wrap_entity_handlers!(
+ get_container,
+ get_container_handler,
+ GetContainerResponse,
+ create_container,
+ create_container_handler,
+ CreateContainerResponse,
+ create_container_batch,
+ create_container_batch_handler,
+ CreateContainerBatchResponse,
+ get_container_history,
+ get_container_history_handler,
+ GetContainerHistoryResponse,
+ ContainerEntity
+ );
+
+ wrap_entity_handlers!(
+ get_creator,
+ get_creator_handler,
+ GetCreatorResponse,
+ create_creator,
+ create_creator_handler,
+ CreateCreatorResponse,
+ create_creator_batch,
+ create_creator_batch_handler,
+ CreateCreatorBatchResponse,
+ get_creator_history,
+ get_creator_history_handler,
+ GetCreatorHistoryResponse,
+ CreatorEntity
+ );
+ wrap_entity_handlers!(
+ get_file,
+ get_file_handler,
+ GetFileResponse,
+ create_file,
+ create_file_handler,
+ CreateFileResponse,
+ create_file_batch,
+ create_file_batch_handler,
+ CreateFileBatchResponse,
+ get_file_history,
+ get_file_history_handler,
+ GetFileHistoryResponse,
+ FileEntity
+ );
+ wrap_entity_handlers!(
+ get_release,
+ get_release_handler,
+ GetReleaseResponse,
+ create_release,
+ create_release_handler,
+ CreateReleaseResponse,
+ create_release_batch,
+ create_release_batch_handler,
+ CreateReleaseBatchResponse,
+ get_release_history,
+ get_release_history_handler,
+ GetReleaseHistoryResponse,
+ ReleaseEntity
+ );
+ wrap_entity_handlers!(
+ get_work,
+ get_work_handler,
+ GetWorkResponse,
+ create_work,
+ create_work_handler,
+ CreateWorkResponse,
+ create_work_batch,
+ create_work_batch_handler,
+ CreateWorkBatchResponse,
+ get_work_history,
+ get_work_history_handler,
+ GetWorkHistoryResponse,
+ WorkEntity
+ );
+
+ wrap_lookup_handler!(
+ lookup_container,
+ lookup_container_handler,
+ LookupContainerResponse,
+ issnl,
+ String
+ );
+ wrap_lookup_handler!(
+ lookup_creator,
+ lookup_creator_handler,
+ LookupCreatorResponse,
+ orcid,
+ String
+ );
+ wrap_lookup_handler!(
+ lookup_file,
+ lookup_file_handler,
+ LookupFileResponse,
+ sha1,
+ String
+ );
+ wrap_lookup_handler!(
+ lookup_release,
+ lookup_release_handler,
+ LookupReleaseResponse,
+ doi,
+ String
+ );
+
+ wrap_lookup_handler!(
+ get_release_files,
+ get_release_files_handler,
+ GetReleaseFilesResponse,
+ id,
+ String
+ );
+ wrap_lookup_handler!(
+ get_work_releases,
+ get_work_releases_handler,
+ GetWorkReleasesResponse,
+ id,
+ String
+ );
+ wrap_lookup_handler!(
+ get_creator_releases,
+ get_creator_releases_handler,
+ GetCreatorReleasesResponse,
+ id,
+ String
+ );
+
+ fn accept_editgroup(
+ &self,
+ id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> {
+
+ let ret = match self.accept_editgroup_handler(id) {
+ Ok(()) => AcceptEditgroupResponse::MergedSuccessfully(Success {
+ message: "horray!".to_string(),
+ }),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ AcceptEditgroupResponse::NotFound(
+ ErrorResponse { message: format!("No such editgroup: {}", id) }),
+ Err(e) =>
+ AcceptEditgroupResponse::GenericError(
+ ErrorResponse { message: e.to_string() }),
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_editgroup(
+ &self,
+ id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {
+ let ret = match self.get_editgroup_handler(id) {
+ Ok(entity) =>
+ GetEditgroupResponse::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ GetEditgroupResponse::NotFound(
+ ErrorResponse { message: format!("No such editgroup: {}", id) }),
+ Err(e) =>
+ // TODO: dig in to error type here
+ GetEditgroupResponse::GenericError(
+ ErrorResponse { message: e.to_string() }),
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn create_editgroup(
+ &self,
+ entity: models::Editgroup,
+ _context: &Context,
+ ) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> {
+
+ let ret = match self.create_editgroup_handler(entity) {
+ Ok(eg) =>
+ CreateEditgroupResponse::SuccessfullyCreated(eg),
+ Err(e) =>
+ // TODO: dig in to error type here
+ CreateEditgroupResponse::GenericError(
+ ErrorResponse { message: e.to_string() }),
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_editor_changelog(
+ &self,
+ username: String,
+ _context: &Context,
+ ) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send> {
+ let ret = match self.editor_changelog_get_handler(username.clone()) {
+ Ok(entries) => GetEditorChangelogResponse::FoundMergedChanges(entries),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ GetEditorChangelogResponse::NotFound(ErrorResponse {
+ message: format!("No such editor: {}", username.clone()),
+ })
+ }
+ Err(e) => {
+ // TODO: dig in to error type here
+ error!("{}", e);
+ GetEditorChangelogResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_editor(
+ &self,
+ username: String,
+ _context: &Context,
+ ) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {
+ let ret = match self.get_editor_handler(username.clone()) {
+ Ok(entity) => GetEditorResponse::FoundEditor(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ GetEditorResponse::NotFound(ErrorResponse {
+ message: format!("No such editor: {}", username.clone()),
+ })
+ }
+ Err(e) => {
+ // TODO: dig in to error type here
+ error!("{}", e);
+ GetEditorResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_changelog(
+ &self,
+ limit: Option<i64>,
+ _context: &Context,
+ ) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> {
+ let ret = match self.get_changelog_handler(limit) {
+ Ok(changelog) => GetChangelogResponse::Success(changelog),
+ Err(e) => {
+ error!("{}", e);
+ GetChangelogResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_changelog_entry(
+ &self,
+ id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> {
+ let ret = match self.get_changelog_entry_handler(id) {
+ Ok(entry) => GetChangelogEntryResponse::FoundChangelogEntry(entry),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ GetChangelogEntryResponse::NotFound(ErrorResponse {
+ message: format!("No such changelog entry: {}", id),
+ })
+ }
+ Err(e) => {
+ error!("{}", e);
+ GetChangelogEntryResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_stats(
+ &self,
+ more: Option<String>,
+ _context: &Context,
+ ) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> {
+ let ret = match self.get_stats_handler(more.clone()) {
+ Ok(stats) => GetStatsResponse::Success(stats),
+ Err(e) => {
+ error!("{}", e);
+ GetStatsResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+}