diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2018-06-17 17:01:23 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2018-06-17 17:01:23 -0700 | 
| commit | c1613504dbe96951ae59889fc11b0564cfbbcd83 (patch) | |
| tree | 9c4aedd480e463a40691ac3cdd50d43fbe15fffe /rust | |
| parent | f3241d35dbb445b7e3c15f1759431580d830bffe (diff) | |
| download | fatcat-c1613504dbe96951ae59889fc11b0564cfbbcd83.tar.gz fatcat-c1613504dbe96951ae59889fc11b0564cfbbcd83.zip | |
update fatcat-api with openapi change
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/fatcat-api/README.md | 5 | ||||
| -rw-r--r-- | rust/fatcat-api/api.yaml | 48 | ||||
| -rw-r--r-- | rust/fatcat-api/api/swagger.yaml | 162 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/client.rs | 22 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/server_lib/server.rs | 24 | ||||
| -rw-r--r-- | rust/fatcat-api/src/client.rs | 185 | ||||
| -rw-r--r-- | rust/fatcat-api/src/lib.rs | 60 | ||||
| -rw-r--r-- | rust/fatcat-api/src/mimetypes.rs | 48 | ||||
| -rw-r--r-- | rust/fatcat-api/src/server.rs | 269 | 
9 files changed, 813 insertions, 10 deletions
| diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 57f877d2..2a969005 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here:  [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md)  - API version: 0.1.0 -- Build date: 2018-06-04T07:14:27.260Z +- Build date: 2018-06-17T23:06:55.598Z  This autogenerated project defines an API crate `fatcat` which contains:  * An `Api` trait defining the API in Rust. @@ -70,12 +70,15 @@ cargo run --example client CreateWork  cargo run --example client CreateWorkBatch  cargo run --example client GetContainer  cargo run --example client GetCreator +cargo run --example client GetCreatorReleases  cargo run --example client GetEditgroup  cargo run --example client GetEditor  cargo run --example client GetEditorChangelog  cargo run --example client GetFile  cargo run --example client GetRelease +cargo run --example client GetReleaseFiles  cargo run --example client GetWork +cargo run --example client GetWorkReleases  cargo run --example client LookupContainer  cargo run --example client LookupCreator  cargo run --example client LookupFile diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index c53ff4a7..44fde1f6 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -438,6 +438,22 @@ paths:            schema:              $ref: "#/definitions/creator_entity"          <<: *ENTITYRESPONSES +  /creator/{id}/releases: +    parameters: +      - name: id +        in: path +        type: string +        required: true +    get: +      operationId: "get_creator_releases" +      responses: +        200: +          description: Found Entity +          schema: +            type: array +            items: +              $ref: "#/definitions/release_entity" +        <<: *ENTITYRESPONSES    /creator/lookup:      get:        operationId: "lookup_creator" @@ -562,6 +578,22 @@ paths:            schema:              $ref: "#/definitions/release_entity"          <<: *ENTITYRESPONSES +  /release/{id}/files: +    parameters: +      - name: id +        in: path +        type: string +        required: true +    get: +      operationId: "get_release_files" +      responses: +        200: +          description: Found Entity +          schema: +            type: array +            items: +              $ref: "#/definitions/file_entity" +        <<: *ENTITYRESPONSES    /release/lookup:      get:        operationId: "lookup_release" @@ -624,6 +656,22 @@ paths:            schema:              $ref: "#/definitions/work_entity"          <<: *ENTITYRESPONSES +  /work/{id}/releases: +    parameters: +      - name: id +        in: path +        type: string +        required: true +    get: +      operationId: "get_work_releases" +      responses: +        200: +          description: Found Entity +          schema: +            type: array +            items: +              $ref: "#/definitions/release_entity" +        <<: *ENTITYRESPONSES    /editor/{username}:      parameters:        - name: username diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index 2a847e1c..d34061fe 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -407,6 +407,60 @@ paths:        path: "/creator/:id"        HttpMethod: "Get"        httpmethod: "get" +  /creator/{id}/releases: +    get: +      operationId: "get_creator_releases" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      responses: +        200: +          description: "Found Entity" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/release_entity" +          x-responseId: "FoundEntity" +          x-uppercaseResponseId: "FOUND_ENTITY" +          uppercase_operation_id: "GET_CREATOR_RELEASES" +          uppercase_data_type: "VEC<RELEASEENTITY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_CREATOR_RELEASES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_CREATOR_RELEASES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        default: +          description: "Generic Error" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "GenericError" +          x-uppercaseResponseId: "GENERIC_ERROR" +          uppercase_operation_id: "GET_CREATOR_RELEASES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_creator_releases" +      uppercase_operation_id: "GET_CREATOR_RELEASES" +      path: "/creator/:id/releases" +      HttpMethod: "Get" +      httpmethod: "get"    /creator/lookup:      get:        operationId: "lookup_creator" @@ -853,6 +907,60 @@ paths:        path: "/release/:id"        HttpMethod: "Get"        httpmethod: "get" +  /release/{id}/files: +    get: +      operationId: "get_release_files" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      responses: +        200: +          description: "Found Entity" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/file_entity" +          x-responseId: "FoundEntity" +          x-uppercaseResponseId: "FOUND_ENTITY" +          uppercase_operation_id: "GET_RELEASE_FILES" +          uppercase_data_type: "VEC<FILEENTITY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_RELEASE_FILES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_RELEASE_FILES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        default: +          description: "Generic Error" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "GenericError" +          x-uppercaseResponseId: "GENERIC_ERROR" +          uppercase_operation_id: "GET_RELEASE_FILES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_release_files" +      uppercase_operation_id: "GET_RELEASE_FILES" +      path: "/release/:id/files" +      HttpMethod: "Get" +      httpmethod: "get"    /release/lookup:      get:        operationId: "lookup_release" @@ -1076,6 +1184,60 @@ paths:        path: "/work/:id"        HttpMethod: "Get"        httpmethod: "get" +  /work/{id}/releases: +    get: +      operationId: "get_work_releases" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      responses: +        200: +          description: "Found Entity" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/release_entity" +          x-responseId: "FoundEntity" +          x-uppercaseResponseId: "FOUND_ENTITY" +          uppercase_operation_id: "GET_WORK_RELEASES" +          uppercase_data_type: "VEC<RELEASEENTITY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_WORK_RELEASES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_WORK_RELEASES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        default: +          description: "Generic Error" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "GenericError" +          x-uppercaseResponseId: "GENERIC_ERROR" +          uppercase_operation_id: "GET_WORK_RELEASES" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_work_releases" +      uppercase_operation_id: "GET_WORK_RELEASES" +      path: "/work/:id/releases" +      HttpMethod: "Get" +      httpmethod: "get"    /editor/{username}:      get:        operationId: "get_editor" diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index ebbff568..cf53eb75 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -13,8 +13,8 @@ use clap::{App, Arg};  #[allow(unused_imports)]  use fatcat::{AcceptEditgroupResponse, ApiError, ApiNoContext, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse,               CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, -             GetContainerResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseResponse, GetWorkResponse, -             LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +             GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, +             GetReleaseResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  #[allow(unused_imports)]  use futures::{future, stream, Future, Stream}; @@ -32,12 +32,15 @@ fn main() {                      "CreateWorkBatch",                      "GetContainer",                      "GetCreator", +                    "GetCreatorReleases",                      "GetEditgroup",                      "GetEditor",                      "GetEditorChangelog",                      "GetFile",                      "GetRelease", +                    "GetReleaseFiles",                      "GetWork", +                    "GetWorkReleases",                      "LookupContainer",                      "LookupCreator",                      "LookupFile", @@ -141,6 +144,11 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetCreatorReleases") => { +            let result = client.get_creator_releases("id_example".to_string()).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetEditgroup") => {              let result = client.get_editgroup(789).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); @@ -166,11 +174,21 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetReleaseFiles") => { +            let result = client.get_release_files("id_example".to_string()).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetWork") => {              let result = client.get_work("id_example".to_string()).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetWorkReleases") => { +            let result = client.get_work_releases("id_example".to_string()).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("LookupContainer") => {              let result = client.lookup_container("issnl_example".to_string()).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index 81dff430..9ce8b5ff 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -11,9 +11,9 @@ use swagger;  use fatcat::models;  use fatcat::{AcceptEditgroupResponse, Api, ApiError, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, -             CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorResponse, -             GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, -             LookupFileResponse, LookupReleaseResponse}; +             CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, +             GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, +             GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  #[derive(Copy, Clone)]  pub struct Server; @@ -107,6 +107,12 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_creator_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!("get_creator_releases(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_editgroup(&self, id: i64, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_editgroup({}) - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); @@ -137,12 +143,24 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_release_files(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!("get_release_files(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_work(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_work(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone());          Box::new(futures::failed("Generic failure".into()))      } +    fn get_work_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!("get_work_releases(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn lookup_container(&self, issnl: String, context: &Context) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("lookup_container(\"{}\") - X-Span-ID: {:?}", issnl, context.x_span_id.unwrap_or(String::from("<none>")).clone()); diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index 978ce597..c5c4a320 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -35,8 +35,9 @@ use swagger::{ApiError, Context, XSpanId};  use models;  use {AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, -     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorResponse, GetEditgroupResponse, -     GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, +     GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, GetWorkReleasesResponse, GetWorkResponse, +     LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  /// 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> { @@ -1049,6 +1050,66 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_creator_releases(&self, param_id: String, context: &Context) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send> { +        let url = format!("{}/v0/creator/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &url); +        let mut custom_headers = hyper::header::Headers::new(); + +        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<GetCreatorReleasesResponse, ApiError> { +            match response.status.to_u16() { +                200 => { +                    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::ReleaseEntity>>(&buf)?; + +                    Ok(GetCreatorReleasesResponse::FoundEntity(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(GetCreatorReleasesResponse::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(GetCreatorReleasesResponse::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(GetCreatorReleasesResponse::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 get_editgroup(&self, param_id: i64, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {          let url = format!("{}/v0/editgroup/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -1343,6 +1404,66 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_release_files(&self, param_id: String, context: &Context) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send> { +        let url = format!("{}/v0/release/{id}/files", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &url); +        let mut custom_headers = hyper::header::Headers::new(); + +        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<GetReleaseFilesResponse, ApiError> { +            match response.status.to_u16() { +                200 => { +                    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::FileEntity>>(&buf)?; + +                    Ok(GetReleaseFilesResponse::FoundEntity(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(GetReleaseFilesResponse::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(GetReleaseFilesResponse::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(GetReleaseFilesResponse::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 get_work(&self, param_id: String, context: &Context) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send> {          let url = format!("{}/v0/work/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -1403,6 +1524,66 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_work_releases(&self, param_id: String, context: &Context) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send> { +        let url = format!("{}/v0/work/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &url); +        let mut custom_headers = hyper::header::Headers::new(); + +        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<GetWorkReleasesResponse, ApiError> { +            match response.status.to_u16() { +                200 => { +                    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::ReleaseEntity>>(&buf)?; + +                    Ok(GetWorkReleasesResponse::FoundEntity(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(GetWorkReleasesResponse::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(GetWorkReleasesResponse::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(GetWorkReleasesResponse::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 lookup_container(&self, param_issnl: String, context: &Context) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send> {          // Query parameters          let query_issnl = format!("issnl={issnl}&", issnl = param_issnl.to_string()); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index d16644ab..c926966e 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -199,6 +199,18 @@ pub enum GetCreatorResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetCreatorReleasesResponse { +    /// Found Entity +    FoundEntity(Vec<models::ReleaseEntity>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetEditgroupResponse {      /// Found Entity      FoundEntity(models::Editgroup), @@ -255,6 +267,18 @@ pub enum GetReleaseResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetReleaseFilesResponse { +    /// Found Entity +    FoundEntity(Vec<models::FileEntity>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetWorkResponse {      /// Found Entity      FoundEntity(models::WorkEntity), @@ -267,6 +291,18 @@ pub enum GetWorkResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetWorkReleasesResponse { +    /// Found Entity +    FoundEntity(Vec<models::ReleaseEntity>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum LookupContainerResponse {      /// Found Entity      FoundEntity(models::ContainerEntity), @@ -344,6 +380,8 @@ pub trait Api {      fn get_creator(&self, id: String, context: &Context) -> Box<Future<Item = GetCreatorResponse, Error = ApiError> + Send>; +    fn get_creator_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send>; +      fn get_editgroup(&self, id: i64, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>;      fn get_editor(&self, username: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send>; @@ -354,8 +392,12 @@ pub trait Api {      fn get_release(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send>; +    fn get_release_files(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send>; +      fn get_work(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send>; +    fn get_work_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send>; +      fn lookup_container(&self, issnl: String, context: &Context) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send>;      fn lookup_creator(&self, orcid: String, context: &Context) -> Box<Future<Item = LookupCreatorResponse, Error = ApiError> + Send>; @@ -395,6 +437,8 @@ pub trait ApiNoContext {      fn get_creator(&self, id: String) -> Box<Future<Item = GetCreatorResponse, Error = ApiError> + Send>; +    fn get_creator_releases(&self, id: String) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send>; +      fn get_editgroup(&self, id: i64) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>;      fn get_editor(&self, username: String) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send>; @@ -405,8 +449,12 @@ pub trait ApiNoContext {      fn get_release(&self, id: String) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send>; +    fn get_release_files(&self, id: String) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send>; +      fn get_work(&self, id: String) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send>; +    fn get_work_releases(&self, id: String) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send>; +      fn lookup_container(&self, issnl: String) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send>;      fn lookup_creator(&self, orcid: String) -> Box<Future<Item = LookupCreatorResponse, Error = ApiError> + Send>; @@ -488,6 +536,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_creator(id, &self.context())      } +    fn get_creator_releases(&self, id: String) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send> { +        self.api().get_creator_releases(id, &self.context()) +    } +      fn get_editgroup(&self, id: i64) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {          self.api().get_editgroup(id, &self.context())      } @@ -508,10 +560,18 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_release(id, &self.context())      } +    fn get_release_files(&self, id: String) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send> { +        self.api().get_release_files(id, &self.context()) +    } +      fn get_work(&self, id: String) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send> {          self.api().get_work(id, &self.context())      } +    fn get_work_releases(&self, id: String) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send> { +        self.api().get_work_releases(id, &self.context()) +    } +      fn lookup_container(&self, issnl: String) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send> {          self.api().lookup_container(issnl, &self.context())      } diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs index 323f28f0..68e5ec04 100644 --- a/rust/fatcat-api/src/mimetypes.rs +++ b/rust/fatcat-api/src/mimetypes.rs @@ -224,6 +224,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetCreatorReleases +    lazy_static! { +        pub static ref GET_CREATOR_RELEASES_FOUND_ENTITY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetCreatorReleases +    lazy_static! { +        pub static ref GET_CREATOR_RELEASES_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetCreatorReleases +    lazy_static! { +        pub static ref GET_CREATOR_RELEASES_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetCreatorReleases +    lazy_static! { +        pub static ref GET_CREATOR_RELEASES_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetEditgroup      lazy_static! {          pub static ref GET_EDITGROUP_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -296,6 +312,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_RELEASE_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetReleaseFiles +    lazy_static! { +        pub static ref GET_RELEASE_FILES_FOUND_ENTITY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetReleaseFiles +    lazy_static! { +        pub static ref GET_RELEASE_FILES_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetReleaseFiles +    lazy_static! { +        pub static ref GET_RELEASE_FILES_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetReleaseFiles +    lazy_static! { +        pub static ref GET_RELEASE_FILES_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetWork      lazy_static! {          pub static ref GET_WORK_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -312,6 +344,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_WORK_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetWorkReleases +    lazy_static! { +        pub static ref GET_WORK_RELEASES_FOUND_ENTITY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetWorkReleases +    lazy_static! { +        pub static ref GET_WORK_RELEASES_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetWorkReleases +    lazy_static! { +        pub static ref GET_WORK_RELEASES_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetWorkReleases +    lazy_static! { +        pub static ref GET_WORK_RELEASES_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for LookupContainer      lazy_static! {          pub static ref LOOKUP_CONTAINER_FOUND_ENTITY: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 3e003783..2716dfc5 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -37,8 +37,9 @@ use swagger::{ApiError, Context, XSpanId};  #[allow(unused_imports)]  use models;  use {AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, -     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorResponse, GetEditgroupResponse, -     GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, +     GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, GetWorkReleasesResponse, GetWorkResponse, +     LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  header! { (Warning, "Warning") => [String] } @@ -1504,6 +1505,94 @@ where      let api_clone = api.clone();      router.get( +        "/v0/creator/:id/releases", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; +                    percent_decode(param.as_bytes()) +                        .decode_utf8() +                        .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? +                        .parse() +                        .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? +                }; + +                match api.get_creator_releases(param_id, context).wait() { +                    Ok(rsp) => match rsp { +                        GetCreatorReleasesResponse::FoundEntity(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(200), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_FOUND_ENTITY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetCreatorReleasesResponse::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::GET_CREATOR_RELEASES_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetCreatorReleasesResponse::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::GET_CREATOR_RELEASES_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetCreatorReleasesResponse::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::GET_CREATOR_RELEASES_GENERIC_ERROR.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            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) +            }) +        }, +        "GetCreatorReleases", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/editgroup/:id",          move |req: &mut Request| {              let mut context = Context::default(); @@ -1924,6 +2013,94 @@ where      let api_clone = api.clone();      router.get( +        "/v0/release/:id/files", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; +                    percent_decode(param.as_bytes()) +                        .decode_utf8() +                        .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? +                        .parse() +                        .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? +                }; + +                match api.get_release_files(param_id, context).wait() { +                    Ok(rsp) => match rsp { +                        GetReleaseFilesResponse::FoundEntity(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(200), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_FOUND_ENTITY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetReleaseFilesResponse::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::GET_RELEASE_FILES_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetReleaseFilesResponse::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::GET_RELEASE_FILES_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetReleaseFilesResponse::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::GET_RELEASE_FILES_GENERIC_ERROR.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            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) +            }) +        }, +        "GetReleaseFiles", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/work/:id",          move |req: &mut Request| {              let mut context = Context::default(); @@ -2012,6 +2189,94 @@ where      let api_clone = api.clone();      router.get( +        "/v0/work/:id/releases", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; +                    percent_decode(param.as_bytes()) +                        .decode_utf8() +                        .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? +                        .parse() +                        .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? +                }; + +                match api.get_work_releases(param_id, context).wait() { +                    Ok(rsp) => match rsp { +                        GetWorkReleasesResponse::FoundEntity(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(200), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_FOUND_ENTITY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetWorkReleasesResponse::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::GET_WORK_RELEASES_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetWorkReleasesResponse::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::GET_WORK_RELEASES_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetWorkReleasesResponse::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::GET_WORK_RELEASES_GENERIC_ERROR.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            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) +            }) +        }, +        "GetWorkReleases", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/container/lookup",          move |req: &mut Request| {              let mut context = Context::default(); | 
