diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2018-06-19 18:31:55 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2018-06-19 18:31:55 -0700 | 
| commit | d2f50808ef9b96afc36d864adec74f10c9cea9af (patch) | |
| tree | 18d563e5570e9b1d578326664e7fe1cf3bc8ea9e /rust/fatcat-api | |
| parent | b262ad227ba5293e210f1137e8080be0796a8c86 (diff) | |
| download | fatcat-d2f50808ef9b96afc36d864adec74f10c9cea9af.tar.gz fatcat-d2f50808ef9b96afc36d864adec74f10c9cea9af.zip | |
implement (most) of stats endpoint
Diffstat (limited to 'rust/fatcat-api')
| -rw-r--r-- | rust/fatcat-api/README.md | 3 | ||||
| -rw-r--r-- | rust/fatcat-api/api.yaml | 24 | ||||
| -rw-r--r-- | rust/fatcat-api/api/swagger.yaml | 42 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/client.rs | 8 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/server_lib/server.rs | 8 | ||||
| -rw-r--r-- | rust/fatcat-api/src/client.rs | 51 | ||||
| -rw-r--r-- | rust/fatcat-api/src/lib.rs | 16 | ||||
| -rw-r--r-- | rust/fatcat-api/src/mimetypes.rs | 8 | ||||
| -rw-r--r-- | rust/fatcat-api/src/models.rs | 13 | ||||
| -rw-r--r-- | rust/fatcat-api/src/server.rs | 60 | 
10 files changed, 227 insertions, 6 deletions
| diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 2a969005..4b40f7ee 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-17T23:06:55.598Z +- Build date: 2018-06-20T01:30:08.472Z  This autogenerated project defines an API crate `fatcat` which contains:  * An `Api` trait defining the API in Rust. @@ -77,6 +77,7 @@ cargo run --example client GetEditorChangelog  cargo run --example client GetFile  cargo run --example client GetRelease  cargo run --example client GetReleaseFiles +cargo run --example client GetStats  cargo run --example client GetWork  cargo run --example client GetWorkReleases  cargo run --example client LookupContainer diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index 44fde1f6..253cec04 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -39,7 +39,6 @@ x-entity-props: &ENTITYPROPS      type: object      additionalProperties: {} -  definitions:    error_response:      type: object @@ -312,6 +311,12 @@ definitions:          type: string        role:          type: string +  stats_response: +    type: object +    properties: +      extra: +        type: object +        additionalProperties: {}  x-entity-responses: &ENTITYRESPONSES    400: @@ -788,3 +793,20 @@ paths:            description: Generic Error            schema:              $ref: "#/definitions/error_response" +  /stats: +    get: +      operationId: "get_stats" +      parameters: +        - name: more +          in: query +          type: string +          required: false +      responses: +        200: +          description: Success +          schema: +            $ref: "#/definitions/stats_response" +        default: +          description: Generic Error +          schema: +            $ref: "#/definitions/error_response" diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index d34061fe..3740cbb2 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -1480,6 +1480,40 @@ paths:        path: "/editgroup/:id/accept"        HttpMethod: "Post"        httpmethod: "post" +  /stats: +    get: +      operationId: "get_stats" +      parameters: +      - name: "more" +        in: "query" +        required: false +        type: "string" +        formatString: "{:?}" +        example: "Some(\"more_example\".to_string())" +      responses: +        200: +          description: "Success" +          schema: +            $ref: "#/definitions/stats_response" +          x-responseId: "Success" +          x-uppercaseResponseId: "SUCCESS" +          uppercase_operation_id: "GET_STATS" +          uppercase_data_type: "STATSRESPONSE" +          producesJson: true +        default: +          description: "Generic Error" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "GenericError" +          x-uppercaseResponseId: "GENERIC_ERROR" +          uppercase_operation_id: "GET_STATS" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_stats" +      uppercase_operation_id: "GET_STATS" +      path: "/stats" +      HttpMethod: "Get" +      httpmethod: "get"  definitions:    error_response:      type: "object" @@ -2016,6 +2050,14 @@ definitions:        index: 1        raw: "raw"      upperCaseName: "RELEASE_CONTRIB" +  stats_response: +    type: "object" +    properties: +      extra: +        type: "object" +    example: +      extra: "{}" +    upperCaseName: "STATS_RESPONSE"    editgroup_edits:      properties:        containers: diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index cf53eb75..28fac094 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -14,7 +14,7 @@ use clap::{App, Arg};  use fatcat::{AcceptEditgroupResponse, ApiError, ApiNoContext, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse,               CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse,               GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, -             GetReleaseResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +             GetReleaseResponse, GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  #[allow(unused_imports)]  use futures::{future, stream, Future, Stream}; @@ -39,6 +39,7 @@ fn main() {                      "GetFile",                      "GetRelease",                      "GetReleaseFiles", +                    "GetStats",                      "GetWork",                      "GetWorkReleases",                      "LookupContainer", @@ -179,6 +180,11 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetStats") => { +            let result = client.get_stats(Some("more_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>"))); diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index 9ce8b5ff..5f4d7acb 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -13,7 +13,7 @@ use fatcat::models;  use fatcat::{AcceptEditgroupResponse, Api, ApiError, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse,               CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse,               GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, -             GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +             GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  #[derive(Copy, Clone)]  pub struct Server; @@ -149,6 +149,12 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_stats(&self, more: Option<String>, context: &Context) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!("get_stats({:?}) - X-Span-ID: {:?}", more, 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()); diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index c5c4a320..809fd1d6 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -36,7 +36,7 @@ use swagger::{ApiError, Context, XSpanId};  use models;  use {AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse,       CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, -     GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, GetWorkReleasesResponse, GetWorkResponse, +     GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse,       LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -1464,6 +1464,55 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_stats(&self, param_more: Option<String>, context: &Context) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_more = param_more.map_or_else(String::new, |query| format!("more={more}&", more = query.to_string())); + +        let url = format!("{}/v0/stats?{more}", self.base_path, more = utf8_percent_encode(&query_more, QUERY_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<GetStatsResponse, 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::<models::StatsResponse>(&buf)?; + +                    Ok(GetStatsResponse::Success(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(GetStatsResponse::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)); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index c926966e..fd0cfe54 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -279,6 +279,14 @@ pub enum GetReleaseFilesResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetStatsResponse { +    /// Success +    Success(models::StatsResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetWorkResponse {      /// Found Entity      FoundEntity(models::WorkEntity), @@ -394,6 +402,8 @@ pub trait Api {      fn get_release_files(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send>; +    fn get_stats(&self, more: Option<String>, context: &Context) -> Box<Future<Item = GetStatsResponse, 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>; @@ -451,6 +461,8 @@ pub trait ApiNoContext {      fn get_release_files(&self, id: String) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send>; +    fn get_stats(&self, more: Option<String>) -> Box<Future<Item = GetStatsResponse, 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>; @@ -564,6 +576,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_release_files(id, &self.context())      } +    fn get_stats(&self, more: Option<String>) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> { +        self.api().get_stats(more, &self.context()) +    } +      fn get_work(&self, id: String) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send> {          self.api().get_work(id, &self.context())      } diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs index 68e5ec04..be7e792f 100644 --- a/rust/fatcat-api/src/mimetypes.rs +++ b/rust/fatcat-api/src/mimetypes.rs @@ -328,6 +328,14 @@ pub mod responses {      lazy_static! {          pub static ref GET_RELEASE_FILES_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetStats +    lazy_static! { +        pub static ref GET_STATS_SUCCESS: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetStats +    lazy_static! { +        pub static ref GET_STATS_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); diff --git a/rust/fatcat-api/src/models.rs b/rust/fatcat-api/src/models.rs index 140e0c2e..15247ce6 100644 --- a/rust/fatcat-api/src/models.rs +++ b/rust/fatcat-api/src/models.rs @@ -618,6 +618,19 @@ impl ReleaseRef {  }  #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct StatsResponse { +    #[serde(rename = "extra")] +    #[serde(skip_serializing_if = "Option::is_none")] +    pub extra: Option<serde_json::Value>, +} + +impl StatsResponse { +    pub fn new() -> StatsResponse { +        StatsResponse { extra: None } +    } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]  pub struct Success {      #[serde(rename = "message")]      pub message: String, diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 2716dfc5..7eb73122 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -38,7 +38,7 @@ use swagger::{ApiError, Context, XSpanId};  use models;  use {AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse,       CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, -     GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, GetWorkReleasesResponse, GetWorkResponse, +     GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse,       LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  header! { (Warning, "Warning") => [String] } @@ -2101,6 +2101,64 @@ where      let api_clone = api.clone();      router.get( +        "/v0/stats", +        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>(); + +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_more = query_params.get("more").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); + +                match api.get_stats(param_more, context).wait() { +                    Ok(rsp) => match rsp { +                        GetStatsResponse::Success(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_STATS_SUCCESS.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetStatsResponse::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_STATS_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) +            }) +        }, +        "GetStats", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/work/:id",          move |req: &mut Request| {              let mut context = Context::default(); | 
