diff options
author | Bryan Newbold <bnewbold@robocracy.org> | 2018-05-27 15:45:03 -0700 |
---|---|---|
committer | Bryan Newbold <bnewbold@robocracy.org> | 2018-05-27 15:45:03 -0700 |
commit | bcb9d2c6793b39b165caf9e63c4803d2a28e9876 (patch) | |
tree | ac8a1a50d7949a48b1c4f6fa5e443ab394cd7ace /rust/fatcat-api/src | |
parent | 19eb1641eece9f03ca193417cdf244efc1a9da8a (diff) | |
download | fatcat-bcb9d2c6793b39b165caf9e63c4803d2a28e9876.tar.gz fatcat-bcb9d2c6793b39b165caf9e63c4803d2a28e9876.zip |
batch POST methods
Diffstat (limited to 'rust/fatcat-api/src')
-rw-r--r-- | rust/fatcat-api/src/client.rs | 332 | ||||
-rw-r--r-- | rust/fatcat-api/src/lib.rs | 100 | ||||
-rw-r--r-- | rust/fatcat-api/src/mimetypes.rs | 100 | ||||
-rw-r--r-- | rust/fatcat-api/src/models.rs | 72 | ||||
-rw-r--r-- | rust/fatcat-api/src/server.rs | 537 |
5 files changed, 1099 insertions, 42 deletions
diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index d81d251f..e9f8bf0e 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -34,9 +34,10 @@ use swagger; use swagger::{ApiError, Context, XSpanId}; use models; -use {Api, ContainerIdGetResponse, ContainerLookupGetResponse, ContainerPostResponse, CreatorIdGetResponse, CreatorLookupGetResponse, CreatorPostResponse, EditgroupIdAcceptPostResponse, - EditgroupIdGetResponse, EditgroupPostResponse, EditorUsernameChangelogGetResponse, EditorUsernameGetResponse, FileIdGetResponse, FileLookupGetResponse, FilePostResponse, ReleaseIdGetResponse, - ReleaseLookupGetResponse, ReleasePostResponse, WorkIdGetResponse, WorkPostResponse}; +use {Api, ContainerBatchPostResponse, ContainerIdGetResponse, ContainerLookupGetResponse, ContainerPostResponse, CreatorBatchPostResponse, CreatorIdGetResponse, CreatorLookupGetResponse, + CreatorPostResponse, EditgroupIdAcceptPostResponse, EditgroupIdGetResponse, EditgroupPostResponse, EditorUsernameChangelogGetResponse, EditorUsernameGetResponse, FileBatchPostResponse, + FileIdGetResponse, FileLookupGetResponse, FilePostResponse, ReleaseBatchPostResponse, ReleaseIdGetResponse, ReleaseLookupGetResponse, ReleasePostResponse, WorkBatchPostResponse, + WorkIdGetResponse, WorkPostResponse}; /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. fn into_base_path<T: IntoUrl>(input: T, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> { @@ -161,6 +162,71 @@ impl Client { } impl Api for Client { + fn container_batch_post(&self, param_entity_list: &Vec<models::ContainerEntity>, context: &Context) -> Box<Future<Item = ContainerBatchPostResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/container/batch", self.base_path); + + let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::CONTAINER_BATCH_POST.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result<ContainerBatchPostResponse, ApiError> { + match response.status.to_u16() { + 201 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<Vec<models::EntityEdit>>(&buf)?; + + Ok(ContainerBatchPostResponse::CreatedEntities(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(ContainerBatchPostResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(ContainerBatchPostResponse::NotFound(body)) + } + 0 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(ContainerBatchPostResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn container_id_get(&self, param_id: String, context: &Context) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError> + Send> { let url = format!("{}/v0/container/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -349,6 +415,71 @@ impl Api for Client { Box::new(futures::done(result)) } + fn creator_batch_post(&self, param_entity_list: &Vec<models::CreatorEntity>, context: &Context) -> Box<Future<Item = CreatorBatchPostResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/creator/batch", self.base_path); + + let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::CREATOR_BATCH_POST.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result<CreatorBatchPostResponse, ApiError> { + match response.status.to_u16() { + 201 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<Vec<models::EntityEdit>>(&buf)?; + + Ok(CreatorBatchPostResponse::CreatedEntities(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(CreatorBatchPostResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(CreatorBatchPostResponse::NotFound(body)) + } + 0 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(CreatorBatchPostResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn creator_id_get(&self, param_id: String, context: &Context) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError> + Send> { let url = format!("{}/v0/creator/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -829,6 +960,71 @@ impl Api for Client { Box::new(futures::done(result)) } + fn file_batch_post(&self, param_entity_list: &Vec<models::FileEntity>, context: &Context) -> Box<Future<Item = FileBatchPostResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/file/batch", self.base_path); + + let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::FILE_BATCH_POST.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result<FileBatchPostResponse, ApiError> { + match response.status.to_u16() { + 201 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<Vec<models::EntityEdit>>(&buf)?; + + Ok(FileBatchPostResponse::CreatedEntities(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(FileBatchPostResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(FileBatchPostResponse::NotFound(body)) + } + 0 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(FileBatchPostResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn file_id_get(&self, param_id: String, context: &Context) -> Box<Future<Item = FileIdGetResponse, Error = ApiError> + Send> { let url = format!("{}/v0/file/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -1017,6 +1213,71 @@ impl Api for Client { Box::new(futures::done(result)) } + fn release_batch_post(&self, param_entity_list: &Vec<models::ReleaseEntity>, context: &Context) -> Box<Future<Item = ReleaseBatchPostResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/release/batch", self.base_path); + + let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::RELEASE_BATCH_POST.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result<ReleaseBatchPostResponse, ApiError> { + match response.status.to_u16() { + 201 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<Vec<models::EntityEdit>>(&buf)?; + + Ok(ReleaseBatchPostResponse::CreatedEntities(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(ReleaseBatchPostResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(ReleaseBatchPostResponse::NotFound(body)) + } + 0 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(ReleaseBatchPostResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn release_id_get(&self, param_id: String, context: &Context) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError> + Send> { let url = format!("{}/v0/release/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -1205,6 +1466,71 @@ impl Api for Client { Box::new(futures::done(result)) } + fn work_batch_post(&self, param_entity_list: &Vec<models::WorkEntity>, context: &Context) -> Box<Future<Item = WorkBatchPostResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/work/batch", self.base_path); + + let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::WORK_BATCH_POST.clone())); + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result<WorkBatchPostResponse, ApiError> { + match response.status.to_u16() { + 201 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<Vec<models::EntityEdit>>(&buf)?; + + Ok(WorkBatchPostResponse::CreatedEntities(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(WorkBatchPostResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(WorkBatchPostResponse::NotFound(body)) + } + 0 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(WorkBatchPostResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + fn work_id_get(&self, param_id: String, context: &Context) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError> + Send> { let url = format!("{}/v0/work/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index dca1aa35..1a46fbeb 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -33,6 +33,18 @@ mod mimetypes; pub use swagger::{ApiError, Context, ContextWrapper}; #[derive(Debug, PartialEq)] +pub enum ContainerBatchPostResponse { + /// Created Entities + CreatedEntities(Vec<models::EntityEdit>), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum ContainerIdGetResponse { /// Found Entity FoundEntity(models::ContainerEntity), @@ -69,6 +81,18 @@ pub enum ContainerPostResponse { } #[derive(Debug, PartialEq)] +pub enum CreatorBatchPostResponse { + /// Created Entities + CreatedEntities(Vec<models::EntityEdit>), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum CreatorIdGetResponse { /// Found Entity FoundEntity(models::CreatorEntity), @@ -159,6 +183,18 @@ pub enum EditorUsernameGetResponse { } #[derive(Debug, PartialEq)] +pub enum FileBatchPostResponse { + /// Created Entities + CreatedEntities(Vec<models::EntityEdit>), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum FileIdGetResponse { /// Found Entity FoundEntity(models::FileEntity), @@ -195,6 +231,18 @@ pub enum FilePostResponse { } #[derive(Debug, PartialEq)] +pub enum ReleaseBatchPostResponse { + /// Created Entities + CreatedEntities(Vec<models::EntityEdit>), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum ReleaseIdGetResponse { /// Found Entity FoundEntity(models::ReleaseEntity), @@ -231,6 +279,18 @@ pub enum ReleasePostResponse { } #[derive(Debug, PartialEq)] +pub enum WorkBatchPostResponse { + /// Created Entities + CreatedEntities(Vec<models::EntityEdit>), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum WorkIdGetResponse { /// Found Entity FoundEntity(models::WorkEntity), @@ -256,12 +316,16 @@ pub enum WorkPostResponse { /// API pub trait Api { + fn container_batch_post(&self, entity_list: &Vec<models::ContainerEntity>, context: &Context) -> Box<Future<Item = ContainerBatchPostResponse, Error = ApiError> + Send>; + fn container_id_get(&self, id: String, context: &Context) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError> + Send>; fn container_lookup_get(&self, issnl: String, context: &Context) -> Box<Future<Item = ContainerLookupGetResponse, Error = ApiError> + Send>; fn container_post(&self, entity: models::ContainerEntity, context: &Context) -> Box<Future<Item = ContainerPostResponse, Error = ApiError> + Send>; + fn creator_batch_post(&self, entity_list: &Vec<models::CreatorEntity>, context: &Context) -> Box<Future<Item = CreatorBatchPostResponse, Error = ApiError> + Send>; + fn creator_id_get(&self, id: String, context: &Context) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError> + Send>; fn creator_lookup_get(&self, orcid: String, context: &Context) -> Box<Future<Item = CreatorLookupGetResponse, Error = ApiError> + Send>; @@ -278,18 +342,24 @@ pub trait Api { fn editor_username_get(&self, username: String, context: &Context) -> Box<Future<Item = EditorUsernameGetResponse, Error = ApiError> + Send>; + fn file_batch_post(&self, entity_list: &Vec<models::FileEntity>, context: &Context) -> Box<Future<Item = FileBatchPostResponse, Error = ApiError> + Send>; + fn file_id_get(&self, id: String, context: &Context) -> Box<Future<Item = FileIdGetResponse, Error = ApiError> + Send>; fn file_lookup_get(&self, sha1: String, context: &Context) -> Box<Future<Item = FileLookupGetResponse, Error = ApiError> + Send>; fn file_post(&self, entity: models::FileEntity, context: &Context) -> Box<Future<Item = FilePostResponse, Error = ApiError> + Send>; + fn release_batch_post(&self, entity_list: &Vec<models::ReleaseEntity>, context: &Context) -> Box<Future<Item = ReleaseBatchPostResponse, Error = ApiError> + Send>; + fn release_id_get(&self, id: String, context: &Context) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError> + Send>; fn release_lookup_get(&self, doi: String, context: &Context) -> Box<Future<Item = ReleaseLookupGetResponse, Error = ApiError> + Send>; fn release_post(&self, entity: models::ReleaseEntity, context: &Context) -> Box<Future<Item = ReleasePostResponse, Error = ApiError> + Send>; + fn work_batch_post(&self, entity_list: &Vec<models::WorkEntity>, context: &Context) -> Box<Future<Item = WorkBatchPostResponse, Error = ApiError> + Send>; + fn work_id_get(&self, id: String, context: &Context) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError> + Send>; fn work_post(&self, entity: models::WorkEntity, context: &Context) -> Box<Future<Item = WorkPostResponse, Error = ApiError> + Send>; @@ -297,12 +367,16 @@ pub trait Api { /// API without a `Context` pub trait ApiNoContext { + fn container_batch_post(&self, entity_list: &Vec<models::ContainerEntity>) -> Box<Future<Item = ContainerBatchPostResponse, Error = ApiError> + Send>; + fn container_id_get(&self, id: String) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError> + Send>; fn container_lookup_get(&self, issnl: String) -> Box<Future<Item = ContainerLookupGetResponse, Error = ApiError> + Send>; fn container_post(&self, entity: models::ContainerEntity) -> Box<Future<Item = ContainerPostResponse, Error = ApiError> + Send>; + fn creator_batch_post(&self, entity_list: &Vec<models::CreatorEntity>) -> Box<Future<Item = CreatorBatchPostResponse, Error = ApiError> + Send>; + fn creator_id_get(&self, id: String) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError> + Send>; fn creator_lookup_get(&self, orcid: String) -> Box<Future<Item = CreatorLookupGetResponse, Error = ApiError> + Send>; @@ -319,18 +393,24 @@ pub trait ApiNoContext { fn editor_username_get(&self, username: String) -> Box<Future<Item = EditorUsernameGetResponse, Error = ApiError> + Send>; + fn file_batch_post(&self, entity_list: &Vec<models::FileEntity>) -> Box<Future<Item = FileBatchPostResponse, Error = ApiError> + Send>; + fn file_id_get(&self, id: String) -> Box<Future<Item = FileIdGetResponse, Error = ApiError> + Send>; fn file_lookup_get(&self, sha1: String) -> Box<Future<Item = FileLookupGetResponse, Error = ApiError> + Send>; fn file_post(&self, entity: models::FileEntity) -> Box<Future<Item = FilePostResponse, Error = ApiError> + Send>; + fn release_batch_post(&self, entity_list: &Vec<models::ReleaseEntity>) -> Box<Future<Item = ReleaseBatchPostResponse, Error = ApiError> + Send>; + fn release_id_get(&self, id: String) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError> + Send>; fn release_lookup_get(&self, doi: String) -> Box<Future<Item = ReleaseLookupGetResponse, Error = ApiError> + Send>; fn release_post(&self, entity: models::ReleaseEntity) -> Box<Future<Item = ReleasePostResponse, Error = ApiError> + Send>; + fn work_batch_post(&self, entity_list: &Vec<models::WorkEntity>) -> Box<Future<Item = WorkBatchPostResponse, Error = ApiError> + Send>; + fn work_id_get(&self, id: String) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError> + Send>; fn work_post(&self, entity: models::WorkEntity) -> Box<Future<Item = WorkPostResponse, Error = ApiError> + Send>; @@ -352,6 +432,10 @@ impl<'a, T: Api + Sized> ContextWrapperExt<'a> for T { } impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { + fn container_batch_post(&self, entity_list: &Vec<models::ContainerEntity>) -> Box<Future<Item = ContainerBatchPostResponse, Error = ApiError> + Send> { + self.api().container_batch_post(entity_list, &self.context()) + } + fn container_id_get(&self, id: String) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError> + Send> { self.api().container_id_get(id, &self.context()) } @@ -364,6 +448,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().container_post(entity, &self.context()) } + fn creator_batch_post(&self, entity_list: &Vec<models::CreatorEntity>) -> Box<Future<Item = CreatorBatchPostResponse, Error = ApiError> + Send> { + self.api().creator_batch_post(entity_list, &self.context()) + } + fn creator_id_get(&self, id: String) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError> + Send> { self.api().creator_id_get(id, &self.context()) } @@ -396,6 +484,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().editor_username_get(username, &self.context()) } + fn file_batch_post(&self, entity_list: &Vec<models::FileEntity>) -> Box<Future<Item = FileBatchPostResponse, Error = ApiError> + Send> { + self.api().file_batch_post(entity_list, &self.context()) + } + fn file_id_get(&self, id: String) -> Box<Future<Item = FileIdGetResponse, Error = ApiError> + Send> { self.api().file_id_get(id, &self.context()) } @@ -408,6 +500,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().file_post(entity, &self.context()) } + fn release_batch_post(&self, entity_list: &Vec<models::ReleaseEntity>) -> Box<Future<Item = ReleaseBatchPostResponse, Error = ApiError> + Send> { + self.api().release_batch_post(entity_list, &self.context()) + } + fn release_id_get(&self, id: String) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError> + Send> { self.api().release_id_get(id, &self.context()) } @@ -420,6 +516,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().release_post(entity, &self.context()) } + fn work_batch_post(&self, entity_list: &Vec<models::WorkEntity>) -> Box<Future<Item = WorkBatchPostResponse, Error = ApiError> + Send> { + self.api().work_batch_post(entity_list, &self.context()) + } + fn work_id_get(&self, id: String) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError> + Send> { self.api().work_id_get(id, &self.context()) } diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs index 5814890f..7b85cac5 100644 --- a/rust/fatcat-api/src/mimetypes.rs +++ b/rust/fatcat-api/src/mimetypes.rs @@ -4,6 +4,22 @@ pub mod responses { use hyper::mime::*; // The macro is called per-operation to beat the recursion limit + /// Create Mime objects for the response content types for ContainerBatchPost + lazy_static! { + pub static ref CONTAINER_BATCH_POST_CREATED_ENTITIES: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for ContainerBatchPost + lazy_static! { + pub static ref CONTAINER_BATCH_POST_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for ContainerBatchPost + lazy_static! { + pub static ref CONTAINER_BATCH_POST_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for ContainerBatchPost + lazy_static! { + pub static ref CONTAINER_BATCH_POST_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for ContainerIdGet lazy_static! { pub static ref CONTAINER_ID_GET_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -52,6 +68,22 @@ pub mod responses { lazy_static! { pub static ref CONTAINER_POST_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for CreatorBatchPost + lazy_static! { + pub static ref CREATOR_BATCH_POST_CREATED_ENTITIES: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreatorBatchPost + lazy_static! { + pub static ref CREATOR_BATCH_POST_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreatorBatchPost + lazy_static! { + pub static ref CREATOR_BATCH_POST_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreatorBatchPost + lazy_static! { + pub static ref CREATOR_BATCH_POST_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for CreatorIdGet lazy_static! { pub static ref CREATOR_ID_GET_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -168,6 +200,22 @@ pub mod responses { lazy_static! { pub static ref EDITOR_USERNAME_GET_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for FileBatchPost + lazy_static! { + pub static ref FILE_BATCH_POST_CREATED_ENTITIES: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for FileBatchPost + lazy_static! { + pub static ref FILE_BATCH_POST_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for FileBatchPost + lazy_static! { + pub static ref FILE_BATCH_POST_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for FileBatchPost + lazy_static! { + pub static ref FILE_BATCH_POST_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for FileIdGet lazy_static! { pub static ref FILE_ID_GET_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -216,6 +264,22 @@ pub mod responses { lazy_static! { pub static ref FILE_POST_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for ReleaseBatchPost + lazy_static! { + pub static ref RELEASE_BATCH_POST_CREATED_ENTITIES: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for ReleaseBatchPost + lazy_static! { + pub static ref RELEASE_BATCH_POST_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for ReleaseBatchPost + lazy_static! { + pub static ref RELEASE_BATCH_POST_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for ReleaseBatchPost + lazy_static! { + pub static ref RELEASE_BATCH_POST_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for ReleaseIdGet lazy_static! { pub static ref RELEASE_ID_GET_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -264,6 +328,22 @@ pub mod responses { lazy_static! { pub static ref RELEASE_POST_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for WorkBatchPost + lazy_static! { + pub static ref WORK_BATCH_POST_CREATED_ENTITIES: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for WorkBatchPost + lazy_static! { + pub static ref WORK_BATCH_POST_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for WorkBatchPost + lazy_static! { + pub static ref WORK_BATCH_POST_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for WorkBatchPost + lazy_static! { + pub static ref WORK_BATCH_POST_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for WorkIdGet lazy_static! { pub static ref WORK_ID_GET_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -301,10 +381,18 @@ pub mod responses { pub mod requests { use hyper::mime::*; + /// Create Mime objects for the request content types for ContainerBatchPost + lazy_static! { + pub static ref CONTAINER_BATCH_POST: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for ContainerPost lazy_static! { pub static ref CONTAINER_POST: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for CreatorBatchPost + lazy_static! { + pub static ref CREATOR_BATCH_POST: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for CreatorPost lazy_static! { pub static ref CREATOR_POST: Mime = mime!(Application / Json); @@ -313,14 +401,26 @@ pub mod requests { lazy_static! { pub static ref EDITGROUP_POST: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for FileBatchPost + lazy_static! { + pub static ref FILE_BATCH_POST: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for FilePost lazy_static! { pub static ref FILE_POST: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for ReleaseBatchPost + lazy_static! { + pub static ref RELEASE_BATCH_POST: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for ReleasePost lazy_static! { pub static ref RELEASE_POST: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for WorkBatchPost + lazy_static! { + pub static ref WORK_BATCH_POST: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for WorkPost lazy_static! { pub static ref WORK_POST: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api/src/models.rs b/rust/fatcat-api/src/models.rs index 24c66f6b..ab18e9b3 100644 --- a/rust/fatcat-api/src/models.rs +++ b/rust/fatcat-api/src/models.rs @@ -113,30 +113,30 @@ pub struct ContainerEntity { #[serde(rename = "name")] pub name: String, - // Note: inline enums are not fully supported by swagger-codegen - #[serde(rename = "state")] - #[serde(skip_serializing_if = "Option::is_none")] - pub state: Option<String>, - - #[serde(rename = "ident")] + #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] - pub ident: Option<String>, + pub extra: Option<serde_json::Value>, - #[serde(rename = "revision")] + #[serde(rename = "editgroup_id")] #[serde(skip_serializing_if = "Option::is_none")] - pub revision: Option<i64>, + pub editgroup_id: Option<i64>, #[serde(rename = "redirect")] #[serde(skip_serializing_if = "Option::is_none")] pub redirect: Option<String>, - #[serde(rename = "editgroup_id")] + #[serde(rename = "revision")] #[serde(skip_serializing_if = "Option::is_none")] - pub editgroup_id: Option<i64>, + pub revision: Option<i64>, - #[serde(rename = "extra")] + #[serde(rename = "ident")] #[serde(skip_serializing_if = "Option::is_none")] - pub extra: Option<serde_json::Value>, + pub ident: Option<String>, + + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option<String>, } impl ContainerEntity { @@ -147,12 +147,12 @@ impl ContainerEntity { issnl: None, publisher: None, name: name, - state: None, - ident: None, - revision: None, - redirect: None, - editgroup_id: None, extra: None, + editgroup_id: None, + redirect: None, + revision: None, + ident: None, + state: None, } } } @@ -166,30 +166,30 @@ pub struct CreatorEntity { #[serde(rename = "full_name")] pub full_name: String, - #[serde(rename = "extra")] - #[serde(skip_serializing_if = "Option::is_none")] - pub extra: Option<serde_json::Value>, - - #[serde(rename = "editgroup_id")] + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] #[serde(skip_serializing_if = "Option::is_none")] - pub editgroup_id: Option<i64>, + pub state: Option<String>, - #[serde(rename = "redirect")] + #[serde(rename = "ident")] #[serde(skip_serializing_if = "Option::is_none")] - pub redirect: Option<String>, + pub ident: Option<String>, #[serde(rename = "revision")] #[serde(skip_serializing_if = "Option::is_none")] pub revision: Option<i64>, - #[serde(rename = "ident")] + #[serde(rename = "redirect")] #[serde(skip_serializing_if = "Option::is_none")] - pub ident: Option<String>, + pub redirect: Option<String>, - // Note: inline enums are not fully supported by swagger-codegen - #[serde(rename = "state")] + #[serde(rename = "editgroup_id")] #[serde(skip_serializing_if = "Option::is_none")] - pub state: Option<String>, + pub editgroup_id: Option<i64>, + + #[serde(rename = "extra")] + #[serde(skip_serializing_if = "Option::is_none")] + pub extra: Option<serde_json::Value>, } impl CreatorEntity { @@ -197,12 +197,12 @@ impl CreatorEntity { CreatorEntity { orcid: None, full_name: full_name, - extra: None, - editgroup_id: None, - redirect: None, - revision: None, - ident: None, state: None, + ident: None, + revision: None, + redirect: None, + editgroup_id: None, + extra: None, } } } diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 7fdc5d2a..0db2c445 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -36,9 +36,10 @@ use swagger::{ApiError, Context, XSpanId}; #[allow(unused_imports)] use models; -use {Api, ContainerIdGetResponse, ContainerLookupGetResponse, ContainerPostResponse, CreatorIdGetResponse, CreatorLookupGetResponse, CreatorPostResponse, EditgroupIdAcceptPostResponse, - EditgroupIdGetResponse, EditgroupPostResponse, EditorUsernameChangelogGetResponse, EditorUsernameGetResponse, FileIdGetResponse, FileLookupGetResponse, FilePostResponse, ReleaseIdGetResponse, - ReleaseLookupGetResponse, ReleasePostResponse, WorkIdGetResponse, WorkPostResponse}; +use {Api, ContainerBatchPostResponse, ContainerIdGetResponse, ContainerLookupGetResponse, ContainerPostResponse, CreatorBatchPostResponse, CreatorIdGetResponse, CreatorLookupGetResponse, + CreatorPostResponse, EditgroupIdAcceptPostResponse, EditgroupIdGetResponse, EditgroupPostResponse, EditorUsernameChangelogGetResponse, EditorUsernameGetResponse, FileBatchPostResponse, + FileIdGetResponse, FileLookupGetResponse, FilePostResponse, ReleaseBatchPostResponse, ReleaseIdGetResponse, ReleaseLookupGetResponse, ReleasePostResponse, WorkBatchPostResponse, + WorkIdGetResponse, WorkPostResponse}; header! { (Warning, "Warning") => [String] } @@ -86,6 +87,112 @@ where T: Api + Send + Sync + Clone + 'static, { let api_clone = api.clone(); + router.post( + "/v0/container/batch", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_entity_list = req.get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_entity_list = if let Some(param_entity_list_raw) = param_entity_list { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_list_raw); + + let param_entity_list: Option<Vec<models::ContainerEntity>> = + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - doesn't match schema: {}", e))))?; + + param_entity_list + } else { + None + }; + let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; + + match api.container_batch_post(param_entity_list.as_ref(), context).wait() { + Ok(rsp) => match rsp { + ContainerBatchPostResponse::CreatedEntities(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::CONTAINER_BATCH_POST_CREATED_ENTITIES.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + ContainerBatchPostResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::CONTAINER_BATCH_POST_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + ContainerBatchPostResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::CONTAINER_BATCH_POST_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + ContainerBatchPostResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(0), body_string)); + response.headers.set(ContentType(mimetypes::responses::CONTAINER_BATCH_POST_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "ContainerBatchPost", + ); + + let api_clone = api.clone(); router.get( "/v0/container/:id", move |req: &mut Request| { @@ -364,6 +471,112 @@ where ); let api_clone = api.clone(); + router.post( + "/v0/creator/batch", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_entity_list = req.get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_entity_list = if let Some(param_entity_list_raw) = param_entity_list { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_list_raw); + + let param_entity_list: Option<Vec<models::CreatorEntity>> = + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - doesn't match schema: {}", e))))?; + + param_entity_list + } else { + None + }; + let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; + + match api.creator_batch_post(param_entity_list.as_ref(), context).wait() { + Ok(rsp) => match rsp { + CreatorBatchPostResponse::CreatedEntities(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATOR_BATCH_POST_CREATED_ENTITIES.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreatorBatchPostResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATOR_BATCH_POST_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreatorBatchPostResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATOR_BATCH_POST_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreatorBatchPostResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(0), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATOR_BATCH_POST_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "CreatorBatchPost", + ); + + let api_clone = api.clone(); router.get( "/v0/creator/:id", move |req: &mut Request| { @@ -1067,6 +1280,112 @@ where ); let api_clone = api.clone(); + router.post( + "/v0/file/batch", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_entity_list = req.get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_entity_list = if let Some(param_entity_list_raw) = param_entity_list { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_list_raw); + + let param_entity_list: Option<Vec<models::FileEntity>> = + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - doesn't match schema: {}", e))))?; + + param_entity_list + } else { + None + }; + let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; + + match api.file_batch_post(param_entity_list.as_ref(), context).wait() { + Ok(rsp) => match rsp { + FileBatchPostResponse::CreatedEntities(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::FILE_BATCH_POST_CREATED_ENTITIES.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + FileBatchPostResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::FILE_BATCH_POST_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + FileBatchPostResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::FILE_BATCH_POST_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + FileBatchPostResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(0), body_string)); + response.headers.set(ContentType(mimetypes::responses::FILE_BATCH_POST_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "FileBatchPost", + ); + + let api_clone = api.clone(); router.get( "/v0/file/:id", move |req: &mut Request| { @@ -1345,6 +1664,112 @@ where ); let api_clone = api.clone(); + router.post( + "/v0/release/batch", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_entity_list = req.get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_entity_list = if let Some(param_entity_list_raw) = param_entity_list { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_list_raw); + + let param_entity_list: Option<Vec<models::ReleaseEntity>> = + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - doesn't match schema: {}", e))))?; + + param_entity_list + } else { + None + }; + let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; + + match api.release_batch_post(param_entity_list.as_ref(), context).wait() { + Ok(rsp) => match rsp { + ReleaseBatchPostResponse::CreatedEntities(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::RELEASE_BATCH_POST_CREATED_ENTITIES.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + ReleaseBatchPostResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::RELEASE_BATCH_POST_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + ReleaseBatchPostResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::RELEASE_BATCH_POST_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + ReleaseBatchPostResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(0), body_string)); + response.headers.set(ContentType(mimetypes::responses::RELEASE_BATCH_POST_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "ReleaseBatchPost", + ); + + let api_clone = api.clone(); router.get( "/v0/release/:id", move |req: &mut Request| { @@ -1623,6 +2048,112 @@ where ); let api_clone = api.clone(); + router.post( + "/v0/work/batch", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_entity_list = req.get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_entity_list = if let Some(param_entity_list_raw) = param_entity_list { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_list_raw); + + let param_entity_list: Option<Vec<models::WorkEntity>> = + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }).map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity_list - doesn't match schema: {}", e))))?; + + param_entity_list + } else { + None + }; + let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; + + match api.work_batch_post(param_entity_list.as_ref(), context).wait() { + Ok(rsp) => match rsp { + WorkBatchPostResponse::CreatedEntities(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::WORK_BATCH_POST_CREATED_ENTITIES.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + WorkBatchPostResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::WORK_BATCH_POST_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + WorkBatchPostResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::WORK_BATCH_POST_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + WorkBatchPostResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(0), body_string)); + response.headers.set(ContentType(mimetypes::responses::WORK_BATCH_POST_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) + } + } + } + + handle_request(req, &api_clone, &mut context).or_else(|mut response| { + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + Ok(response) + }) + }, + "WorkBatchPost", + ); + + let api_clone = api.clone(); router.get( "/v0/work/:id", move |req: &mut Request| { |