From e699baeb74583a9679db43c8632b94d2c2c5212c Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 23 Dec 2020 23:43:21 -0800 Subject: [PATCH] encapsulate use of #[derive(JsonSchema)] --- dropshot/examples/basic.rs | 4 +- dropshot/examples/pagination-basic.rs | 8 +- .../examples/pagination-multiple-resources.rs | 16 ++-- .../examples/pagination-multiple-sorts.rs | 12 +-- dropshot/examples/petstore.rs | 19 +++-- dropshot/src/api_description.rs | 12 +-- dropshot/src/handler.rs | 75 ++++++++++--------- dropshot/src/lib.rs | 24 +++--- dropshot/src/pagination.rs | 24 +++--- dropshot/tests/fail/bad_endpoint4.stderr | 12 +-- dropshot/tests/fail/bad_endpoint5.rs | 4 +- dropshot/tests/fail/bad_endpoint5.stderr | 2 +- dropshot/tests/fail/bad_endpoint6.rs | 4 +- dropshot/tests/fail/bad_endpoint7.rs | 4 +- dropshot/tests/fail/bad_endpoint7.stderr | 12 +-- dropshot/tests/test_demo.rs | 16 ++-- dropshot/tests/test_openapi.rs | 23 +++--- dropshot/tests/test_pagination.rs | 18 +++-- 18 files changed, 152 insertions(+), 137 deletions(-) diff --git a/dropshot/examples/basic.rs b/dropshot/examples/basic.rs index 0dc73210..21f24581 100644 --- a/dropshot/examples/basic.rs +++ b/dropshot/examples/basic.rs @@ -8,13 +8,13 @@ use dropshot::ApiDescription; use dropshot::ConfigDropshot; use dropshot::ConfigLogging; use dropshot::ConfigLoggingLevel; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::HttpResponseUpdatedNoContent; use dropshot::HttpServer; use dropshot::RequestContext; use dropshot::TypedBody; -use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::any::Any; @@ -107,7 +107,7 @@ impl ExampleContext { * response to a GET request to fetch the counter or as the body of a PUT * request to update the counter. */ -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] struct CounterValue { counter: u64, } diff --git a/dropshot/examples/pagination-basic.rs b/dropshot/examples/pagination-basic.rs index 0663686f..6dcb7f3c 100644 --- a/dropshot/examples/pagination-basic.rs +++ b/dropshot/examples/pagination-basic.rs @@ -22,6 +22,7 @@ use dropshot::ConfigDropshot; use dropshot::ConfigLogging; use dropshot::ConfigLoggingLevel; use dropshot::EmptyScanParams; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::HttpServer; @@ -30,7 +31,6 @@ use dropshot::Query; use dropshot::RequestContext; use dropshot::ResultsPage; use dropshot::WhichPage; -use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::collections::BTreeMap; @@ -42,10 +42,10 @@ use std::sync::Arc; /** * Object returned by our paginated endpoint * - * Like anything returned by Dropshot, we must implement `JsonSchema` and + * Like anything returned by Dropshot, we must implement `ExtractedParameter` and * `Serialize`. We also implement `Clone` to simplify the example. */ -#[derive(Clone, JsonSchema, Serialize)] +#[derive(Clone, ExtractedParameter, Serialize)] struct Project { name: String, // lots more fields @@ -61,7 +61,7 @@ struct Project { * include with each page of results, and it must be `Deserialize` to get it * back in a querystring. */ -#[derive(Deserialize, JsonSchema, Serialize)] +#[derive(Deserialize, ExtractedParameter, Serialize)] struct ProjectPage { name: String, } diff --git a/dropshot/examples/pagination-multiple-resources.rs b/dropshot/examples/pagination-multiple-resources.rs index 1501f0d0..ec9a7fa9 100644 --- a/dropshot/examples/pagination-multiple-resources.rs +++ b/dropshot/examples/pagination-multiple-resources.rs @@ -10,6 +10,7 @@ use dropshot::ApiDescription; use dropshot::ConfigDropshot; use dropshot::ConfigLogging; use dropshot::ConfigLoggingLevel; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::HttpServer; @@ -21,7 +22,6 @@ use dropshot::Query; use dropshot::RequestContext; use dropshot::ResultsPage; use dropshot::WhichPage; -use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::collections::BTreeMap; @@ -36,21 +36,21 @@ use uuid::Uuid; * "name". We'll have one endpoint for each resource to list it. */ -#[derive(Clone, JsonSchema, Serialize)] +#[derive(Clone, ExtractedParameter, Serialize)] struct Project { id: Uuid, name: String, // lots more project-like fields } -#[derive(Clone, JsonSchema, Serialize)] +#[derive(Clone, ExtractedParameter, Serialize)] struct Disk { id: Uuid, name: String, // lots more disk-like fields } -#[derive(Clone, JsonSchema, Serialize)] +#[derive(Clone, ExtractedParameter, Serialize)] struct Instance { id: Uuid, name: String, @@ -88,7 +88,7 @@ impl_HasIdentity!(Instance); /* * Pagination-related types */ -#[derive(Deserialize, Clone, JsonSchema, Serialize)] +#[derive(Deserialize, Clone, ExtractedParameter, Serialize)] struct ExScanParams { #[serde(default = "default_sort_mode")] sort: ExSortMode, @@ -98,7 +98,7 @@ fn default_sort_mode() -> ExSortMode { ExSortMode::ByNameAscending } -#[derive(Deserialize, Clone, JsonSchema, Serialize)] +#[derive(Deserialize, Clone, ExtractedParameter, Serialize)] #[serde(rename_all = "kebab-case")] enum ExSortMode { ByIdAscending, @@ -107,7 +107,7 @@ enum ExSortMode { ByNameDescending, } -#[derive(Debug, Deserialize, JsonSchema, Serialize)] +#[derive(Debug, Deserialize, ExtractedParameter, Serialize)] #[serde(rename_all = "kebab-case")] enum ExPageSelector { Id(PaginationOrder, Uuid), @@ -251,7 +251,7 @@ fn do_list<'a, T>( by_id: &'a BTreeMap>, ) -> ItemIter<'a, T> where - T: Clone + JsonSchema + Serialize + Send + Sync + 'static, + T: Clone + ExtractedParameter + Serialize + Send + Sync + 'static, { match p { WhichPage::First(_) => match scan_params.sort { diff --git a/dropshot/examples/pagination-multiple-sorts.rs b/dropshot/examples/pagination-multiple-sorts.rs index 692d3019..92b94bd5 100644 --- a/dropshot/examples/pagination-multiple-sorts.rs +++ b/dropshot/examples/pagination-multiple-sorts.rs @@ -98,6 +98,7 @@ use dropshot::ApiDescription; use dropshot::ConfigDropshot; use dropshot::ConfigLogging; use dropshot::ConfigLoggingLevel; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::HttpServer; @@ -110,7 +111,6 @@ use dropshot::RequestContext; use dropshot::ResultsPage; use dropshot::WhichPage; use hyper::Uri; -use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::collections::BTreeMap; @@ -125,10 +125,10 @@ extern crate slog; /** * Item returned by our paginated endpoint * - * Like anything returned by Dropshot, we must implement `JsonSchema` and + * Like anything returned by Dropshot, we must implement `ExtractedParameter` and * `Serialize`. We also implement `Clone` to simplify the example. */ -#[derive(Clone, JsonSchema, Serialize)] +#[derive(Clone, ExtractedParameter, Serialize)] struct Project { name: String, mtime: DateTime, @@ -148,7 +148,7 @@ struct Project { * serialize it using `serde_querystring`. That code could fail at runtime for * certain types of values (e.g., enum variants that contain data). */ -#[derive(Clone, Deserialize, JsonSchema, Serialize)] +#[derive(Clone, Deserialize, ExtractedParameter, Serialize)] struct ProjectScanParams { #[serde(default = "default_project_sort")] sort: ProjectSort, @@ -158,7 +158,7 @@ fn default_project_sort() -> ProjectSort { ProjectSort::ByNameAscending } -#[derive(Deserialize, Clone, JsonSchema, Serialize)] +#[derive(Deserialize, Clone, ExtractedParameter, Serialize)] #[serde(rename_all = "kebab-case")] enum ProjectSort { /** by name ascending */ @@ -186,7 +186,7 @@ enum ProjectSort { * selector back, you find the object having the next value after the one stored * in the token and start returning results from there. */ -#[derive(Deserialize, JsonSchema, Serialize)] +#[derive(Deserialize, ExtractedParameter, Serialize)] #[serde(rename_all = "kebab-case")] enum ProjectScanPageSelector { Name(PaginationOrder, String), diff --git a/dropshot/examples/petstore.rs b/dropshot/examples/petstore.rs index 4794d7bb..58038406 100644 --- a/dropshot/examples/petstore.rs +++ b/dropshot/examples/petstore.rs @@ -1,8 +1,7 @@ use dropshot::{ - endpoint, ApiDescription, HttpError, HttpResponseOk, PaginationParams, - Path, Query, RequestContext, ResultsPage, TypedBody, + endpoint, ApiDescription, ExtractedParameter, HttpError, HttpResponseOk, + PaginationParams, Path, Query, RequestContext, ResultsPage, TypedBody, }; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -33,7 +32,7 @@ fn main() -> Result<(), String> { } #[allow(dead_code)] -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] #[serde(rename_all = "camelCase")] struct Pet { id: Option, @@ -47,7 +46,7 @@ struct Pet { } #[allow(dead_code)] -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] #[serde(rename_all = "camelCase")] struct Category { id: i64, @@ -55,12 +54,12 @@ struct Category { } #[allow(dead_code)] -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] #[serde(rename_all = "camelCase")] struct Tag {} #[allow(dead_code)] -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] #[serde(rename_all = "lowercase")] enum PetStatus { Available, @@ -69,7 +68,7 @@ enum PetStatus { } #[allow(dead_code)] -#[derive(Deserialize, JsonSchema)] +#[derive(Deserialize, ExtractedParameter)] #[serde(rename_all = "camelCase")] struct PathParams { pet_id: i64, @@ -113,7 +112,7 @@ async fn update_pet_with_form( } #[allow(dead_code)] -#[derive(Deserialize, JsonSchema)] +#[derive(Deserialize, ExtractedParameter)] #[serde(rename_all = "camelCase")] struct FindByTagsScanParams { /// Tags to filter for @@ -121,7 +120,7 @@ struct FindByTagsScanParams { } #[allow(dead_code)] -#[derive(Serialize, Deserialize, JsonSchema)] +#[derive(Serialize, Deserialize, ExtractedParameter)] #[serde(rename_all = "camelCase")] struct FindByTagsPageSelector { tags: String, diff --git a/dropshot/src/api_description.rs b/dropshot/src/api_description.rs index c884db0f..1b6e0b73 100644 --- a/dropshot/src/api_description.rs +++ b/dropshot/src/api_description.rs @@ -856,14 +856,14 @@ mod test { use super::j2oas_schema; use super::ApiDescription; use super::ApiEndpoint; + use crate::ExtractedParameter; use http::Method; use hyper::Body; use hyper::Response; - use schemars::JsonSchema; use serde::Deserialize; use std::sync::Arc; - #[derive(Deserialize, JsonSchema)] + #[derive(Deserialize, ExtractedParameter)] #[allow(dead_code)] struct TestPath { a: String, @@ -927,7 +927,7 @@ mod test { #[test] fn test_empty_struct() { - #[derive(JsonSchema)] + #[derive(ExtractedParameter)] struct Empty {} let settings = schemars::gen::SchemaSettings::openapi3(); @@ -940,7 +940,7 @@ mod test { #[test] fn test_garbage_barge_structure_conversion() { #[allow(dead_code)] - #[derive(JsonSchema)] + #[derive(ExtractedParameter)] struct SuperGarbage { string: String, strings: Vec, @@ -952,7 +952,7 @@ mod test { } #[allow(dead_code)] - #[derive(JsonSchema)] + #[derive(ExtractedParameter)] struct Substruct { ii32: i32, uu64: u64, @@ -962,7 +962,7 @@ mod test { } #[allow(dead_code)] - #[derive(JsonSchema)] + #[derive(ExtractedParameter)] enum Union { A { a: u32 }, B { b: f32 }, diff --git a/dropshot/src/handler.rs b/dropshot/src/handler.rs index dcf0b8d9..91e53018 100644 --- a/dropshot/src/handler.rs +++ b/dropshot/src/handler.rs @@ -500,6 +500,9 @@ where * Extractors */ +pub trait ExtractedParameter: JsonSchema {} +impl ExtractedParameter for T {} + /* * Query: query string extractor */ @@ -510,11 +513,14 @@ where * structure of yours that implements `serde::Deserialize`. See this module's * documentation for more information. */ -pub struct Query { +pub struct Query +{ inner: QueryType, } -impl Query { +impl + Query +{ /* * TODO drop this in favor of Deref? + Display and Debug for convenience? */ @@ -531,7 +537,7 @@ fn http_request_load_query( request: &Request, ) -> Result, HttpError> where - QueryType: DeserializeOwned + JsonSchema + Send + Sync, + QueryType: DeserializeOwned + ExtractedParameter + Send + Sync, { let raw_query_string = request.uri().query().unwrap_or(""); /* @@ -559,7 +565,7 @@ where #[async_trait] impl Extractor for Query where - QueryType: JsonSchema + DeserializeOwned + Send + Sync + 'static, + QueryType: ExtractedParameter + DeserializeOwned + Send + Sync + 'static, { async fn from_request( rqctx: Arc, @@ -583,11 +589,11 @@ where * structure of yours that implements `serde::Deserialize`. See this module's * documentation for more information. */ -pub struct Path { +pub struct Path { inner: PathType, } -impl Path { +impl Path { /* * TODO drop this in favor of Deref? + Display and Debug for convenience? */ @@ -604,7 +610,7 @@ impl Path { #[async_trait] impl Extractor for Path where - PathType: DeserializeOwned + JsonSchema + Send + Sync + 'static, + PathType: DeserializeOwned + ExtractedParameter + Send + Sync + 'static, { async fn from_request( rqctx: Arc, @@ -622,7 +628,7 @@ where /** * Convenience trait to generate parameter metadata from types implementing - * `JsonSchema` for use with `Query` and `Path` `Extractors`. + * `ExtractedParameter` for use with `Query` and `Path` `Extractors`. */ pub(crate) trait GetMetadata { fn metadata( @@ -632,7 +638,7 @@ pub(crate) trait GetMetadata { impl GetMetadata for ParamType where - ParamType: JsonSchema, + ParamType: ExtractedParameter, { fn metadata( loc: &ApiEndpointParameterLocation, @@ -814,11 +820,13 @@ fn schema2parameters( * that implements `serde::Deserialize`. See this module's documentation for * more information. */ -pub struct TypedBody { +pub struct TypedBody< + BodyType: ExtractedParameter + DeserializeOwned + Send + Sync, +> { inner: BodyType, } -impl +impl TypedBody { /* @@ -837,7 +845,7 @@ async fn http_request_load_json_body( rqctx: Arc, ) -> Result, HttpError> where - BodyType: JsonSchema + DeserializeOwned + Send + Sync, + BodyType: ExtractedParameter + DeserializeOwned + Send + Sync, { let server = &rqctx.server; let mut request = rqctx.request.lock().await; @@ -870,7 +878,7 @@ where #[async_trait] impl Extractor for TypedBody where - BodyType: JsonSchema + DeserializeOwned + Send + Sync + 'static, + BodyType: ExtractedParameter + DeserializeOwned + Send + Sync + 'static, { async fn from_request( rqctx: Arc, @@ -946,7 +954,7 @@ impl HttpResponse for Response { pub trait HttpTypedResponse: Into + Send + Sync + 'static { - type Body: JsonSchema + Serialize; + type Body: ExtractedParameter + Serialize; const STATUS_CODE: StatusCode; const DESCRIPTION: &'static str; @@ -995,16 +1003,16 @@ where * field having type T::View). */ pub struct HttpResponseCreated< - T: JsonSchema + Serialize + Send + Sync + 'static, + T: ExtractedParameter + Serialize + Send + Sync + 'static, >(pub T); -impl HttpTypedResponse - for HttpResponseCreated +impl + HttpTypedResponse for HttpResponseCreated { type Body = T; const STATUS_CODE: StatusCode = StatusCode::CREATED; const DESCRIPTION: &'static str = "successful creation"; } -impl +impl From> for HttpHandlerResult { fn from(response: HttpResponseCreated) -> HttpHandlerResult { @@ -1019,16 +1027,16 @@ impl * generated by serializing the object. */ pub struct HttpResponseAccepted< - T: JsonSchema + Serialize + Send + Sync + 'static, + T: ExtractedParameter + Serialize + Send + Sync + 'static, >(pub T); -impl HttpTypedResponse - for HttpResponseAccepted +impl + HttpTypedResponse for HttpResponseAccepted { type Body = T; const STATUS_CODE: StatusCode = StatusCode::ACCEPTED; const DESCRIPTION: &'static str = "successfully enqueued operation"; } -impl +impl From> for HttpHandlerResult { fn from(response: HttpResponseAccepted) -> HttpHandlerResult { @@ -1041,18 +1049,18 @@ impl * denotes an HTTP 200 "OK" response whose body is generated by serializing the * object. */ -pub struct HttpResponseOk( - pub T, -); -impl HttpTypedResponse - for HttpResponseOk +pub struct HttpResponseOk< + T: ExtractedParameter + Serialize + Send + Sync + 'static, +>(pub T); +impl + HttpTypedResponse for HttpResponseOk { type Body = T; const STATUS_CODE: StatusCode = StatusCode::OK; const DESCRIPTION: &'static str = "successful operation"; } -impl From> - for HttpHandlerResult +impl + From> for HttpHandlerResult { fn from(response: HttpResponseOk) -> HttpHandlerResult { HttpResponseOk::for_object(&response.0) @@ -1102,12 +1110,11 @@ mod test { use super::GetMetadata; use crate::{ api_description::ApiEndpointParameterName, ApiEndpointParameter, - ApiEndpointParameterLocation, PaginationParams, + ApiEndpointParameterLocation, ExtractedParameter, PaginationParams, }; - use schemars::JsonSchema; use serde::{Deserialize, Serialize}; - #[derive(Deserialize, Serialize, JsonSchema)] + #[derive(Deserialize, Serialize, ExtractedParameter)] #[allow(dead_code)] struct A { foo: String, @@ -1115,7 +1122,7 @@ mod test { baz: Option, } - #[derive(JsonSchema)] + #[derive(ExtractedParameter)] #[allow(dead_code)] struct B { #[serde(flatten)] @@ -1124,7 +1131,7 @@ mod test { limit: Option, } - #[derive(JsonSchema)] + #[derive(ExtractedParameter)] #[allow(dead_code)] #[schemars(untagged)] enum C { diff --git a/dropshot/src/lib.rs b/dropshot/src/lib.rs index 7d037a57..e87d8da6 100644 --- a/dropshot/src/lib.rs +++ b/dropshot/src/lib.rs @@ -117,16 +117,16 @@ * ``` * use dropshot::endpoint; * use dropshot::ApiDescription; + * use dropshot::ExtractedParameter; * use dropshot::HttpError; * use dropshot::HttpResponseOk; * use dropshot::RequestContext; * use http::Method; - * use schemars::JsonSchema; * use serde::Serialize; * use std::sync::Arc; * * /** Represents a project in our API */ - * #[derive(Serialize, JsonSchema)] + * #[derive(Serialize, ExtractedParameter)] * struct Project { * /** name of the project */ * name: String, @@ -223,13 +223,13 @@ * * * [`Query`]`` extracts parameters from a query string, deserializing them * into an instance of type `Q`. `Q` must implement `serde::Deserialize` and - * `schemars::JsonSchema`. + * `dropshot::ExtractedParameter`. * * [`Path`]`

` extracts parameters from HTTP path, deserializing them into * an instance of type `P`. `P` must implement `serde::Deserialize` and - * `schemars::JsonSchema`. + * `dropshot::ExtractedParameter`. * * [`TypedBody`]`` extracts content from the request body by parsing the * body as JSON and deserializing it into an instance of type `J`. `J` must - * implement `serde::Deserialize` and `schemars::JsonSchema`. + * implement `serde::Deserialize` and `dropshot::ExtractedParameter`. * * If the handler takes a `Query`, `Path

`, or a `TypedBody` and the * corresponding extraction cannot be completed, the request fails with status @@ -242,17 +242,17 @@ * * ``` * use http::StatusCode; + * use dropshot::ExtractedParameter; * use dropshot::HttpError; * use dropshot::TypedBody; * use dropshot::Query; * use dropshot::RequestContext; * use hyper::Body; * use hyper::Response; - * use schemars::JsonSchema; * use serde::Deserialize; * use std::sync::Arc; * - * #[derive(Deserialize, JsonSchema)] + * #[derive(Deserialize, ExtractedParameter)] * struct MyQueryArgs { * limit: u32, * marker: Option @@ -442,6 +442,7 @@ * arguments using `Query`, like this: * * ``` + * use dropshot::ExtractedParameter; * use dropshot::HttpError; * use dropshot::HttpResponseOk; * use dropshot::PaginationParams; @@ -449,15 +450,14 @@ * use dropshot::RequestContext; * use dropshot::ResultsPage; * use dropshot::endpoint; - * use schemars::JsonSchema; * use serde::Deserialize; * use std::sync::Arc; * # use serde::Serialize; - * # #[derive(Debug, Deserialize, JsonSchema)] + * # #[derive(Debug, Deserialize, ExtractedParameter)] * # enum MyScanParams { A }; - * # #[derive(Debug, Deserialize, JsonSchema, Serialize)] + * # #[derive(Debug, Deserialize, ExtractedParameter, Serialize)] * # enum MyPageSelector { A(String) }; - * #[derive(Deserialize, JsonSchema)] + * #[derive(Deserialize, ExtractedParameter)] * struct MyExtraQueryParams { * do_extra_stuff: bool, * } @@ -538,3 +538,5 @@ pub use http::Method; extern crate dropshot_endpoint; pub use dropshot_endpoint::endpoint; + +pub use schemars::JsonSchema as ExtractedParameter; diff --git a/dropshot/src/pagination.rs b/dropshot/src/pagination.rs index f6c5129c..d8a8606b 100644 --- a/dropshot/src/pagination.rs +++ b/dropshot/src/pagination.rs @@ -100,8 +100,8 @@ use crate::error::HttpError; use crate::from_map::from_map; +use crate::ExtractedParameter; use base64::URL_SAFE; -use schemars::JsonSchema; use serde::de::DeserializeOwned; use serde::Deserialize; use serde::Deserializer; @@ -116,7 +116,7 @@ use std::num::NonZeroU64; * This structure is intended for use both on the server side (to generate the * results page) and on the client side (to parse it). */ -#[derive(Debug, Deserialize, JsonSchema, Serialize)] +#[derive(Debug, Deserialize, ExtractedParameter, Serialize)] #[schemars(description = "A single page of results")] pub struct ResultsPage { /** token used to fetch the next page of results (if any) */ @@ -189,7 +189,7 @@ impl ResultsPage { * careful when designing these structures to consider what you might want to * support in the future. */ -#[derive(Debug, Deserialize, JsonSchema)] +#[derive(Debug, Deserialize, ExtractedParameter)] pub struct PaginationParams where ScanParams: DeserializeOwned, @@ -281,12 +281,12 @@ pub enum WhichPage { } /* - * Generate the JsonSchema for WhichPage from SchemaWhichPage. + * Generate the ExtractedParameter for WhichPage from SchemaWhichPage. */ -impl JsonSchema +impl ExtractedParameter for WhichPage where - ScanParams: JsonSchema, + ScanParams: ExtractedParameter, { fn schema_name() -> String { unimplemented!(); @@ -303,13 +303,15 @@ where * scan parameters (i.e., it always iterates items in the collection in the same * way). */ -#[derive(Debug, Deserialize, JsonSchema)] +#[derive(Debug, Deserialize, ExtractedParameter)] pub struct EmptyScanParams {} /** * The order in which the client wants to page through the requested collection */ -#[derive(Copy, Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[derive( + Copy, Clone, Debug, Deserialize, ExtractedParameter, PartialEq, Serialize, +)] #[serde(rename_all = "lowercase")] pub enum PaginationOrder { Ascending, @@ -359,7 +361,9 @@ const MAX_TOKEN_LENGTH: usize = 512; * Note that consumers still need to consider compatibility if they change their * own `ScanParams` or `PageSelector` types. */ -#[derive(Copy, Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[derive( + Copy, Clone, Debug, Deserialize, ExtractedParameter, PartialEq, Serialize, +)] #[serde(rename_all = "lowercase")] enum PaginationVersion { V1, @@ -461,7 +465,7 @@ fn deserialize_page_token( /* * This is the on-the-wire protocol; we use this solely to generate the schema. */ -#[derive(JsonSchema)] +#[derive(ExtractedParameter)] #[allow(dead_code)] #[serde(untagged)] enum SchemaWhichPage { diff --git a/dropshot/tests/fail/bad_endpoint4.stderr b/dropshot/tests/fail/bad_endpoint4.stderr index 40d844dc..2de77093 100644 --- a/dropshot/tests/fail/bad_endpoint4.stderr +++ b/dropshot/tests/fail/bad_endpoint4.stderr @@ -1,13 +1,15 @@ -error[E0277]: the trait bound `QueryParams: schemars::JsonSchema` is not satisfied +error[E0277]: the trait bound `QueryParams: ExtractedParameter` is not satisfied --> $DIR/bad_endpoint4.rs:22:14 | 22 | _params: Query, - | ^^^^^^^^^^^^^^^^^^ the trait `schemars::JsonSchema` is not implemented for `QueryParams` + | ^^^^^^^^^^^^^^^^^^ the trait `ExtractedParameter` is not implemented for `QueryParams` | ::: $WORKSPACE/dropshot/src/handler.rs | - | pub struct Query { - | ---------- required by this bound in `dropshot::Query` + | pub struct Query + | ------------------ required by this bound in `dropshot::Query` + | + = note: required because of the requirements on the impl of `dropshot::handler::ExtractedParameter` for `QueryParams` error[E0277]: the trait bound `for<'de> QueryParams: serde::de::Deserialize<'de>` is not satisfied --> $DIR/bad_endpoint4.rs:22:14 @@ -17,7 +19,7 @@ error[E0277]: the trait bound `for<'de> QueryParams: serde::de::Deserialize<'de> | ::: $WORKSPACE/dropshot/src/handler.rs | - | pub struct Query { + | pub struct Query | ---------------- required by this bound in `dropshot::Query` | = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `QueryParams` diff --git a/dropshot/tests/fail/bad_endpoint5.rs b/dropshot/tests/fail/bad_endpoint5.rs index 46fad665..7eb47b2e 100644 --- a/dropshot/tests/fail/bad_endpoint5.rs +++ b/dropshot/tests/fail/bad_endpoint5.rs @@ -1,14 +1,14 @@ // Copyright 2020 Oxide Computer Company use dropshot::endpoint; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::Query; use dropshot::RequestContext; -use schemars::JsonSchema; use std::sync::Arc; -#[derive(JsonSchema)] +#[derive(ExtractedParameter)] #[allow(dead_code)] struct QueryParams { x: String, diff --git a/dropshot/tests/fail/bad_endpoint5.stderr b/dropshot/tests/fail/bad_endpoint5.stderr index 41495157..aa8fa35f 100644 --- a/dropshot/tests/fail/bad_endpoint5.stderr +++ b/dropshot/tests/fail/bad_endpoint5.stderr @@ -6,7 +6,7 @@ error[E0277]: the trait bound `for<'de> QueryParams: serde::de::Deserialize<'de> | ::: $WORKSPACE/dropshot/src/handler.rs | - | pub struct Query { + | pub struct Query | ---------------- required by this bound in `dropshot::Query` | = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `QueryParams` diff --git a/dropshot/tests/fail/bad_endpoint6.rs b/dropshot/tests/fail/bad_endpoint6.rs index 79db68bb..102786fb 100644 --- a/dropshot/tests/fail/bad_endpoint6.rs +++ b/dropshot/tests/fail/bad_endpoint6.rs @@ -4,10 +4,10 @@ use dropshot::endpoint; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::RequestContext; -use schemars::JsonSchema; +use dropshot::ExtractedParameter; use std::sync::Arc; -#[derive(JsonSchema)] +#[derive(ExtractedParameter)] #[allow(dead_code)] struct Ret { x: String, diff --git a/dropshot/tests/fail/bad_endpoint7.rs b/dropshot/tests/fail/bad_endpoint7.rs index 5563c904..c6bfeed7 100644 --- a/dropshot/tests/fail/bad_endpoint7.rs +++ b/dropshot/tests/fail/bad_endpoint7.rs @@ -1,13 +1,13 @@ // Copyright 2020 Oxide Computer Company use dropshot::endpoint; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::RequestContext; -use schemars::JsonSchema; use std::sync::Arc; -#[derive(JsonSchema)] +#[derive(ExtractedParameter)] #[allow(dead_code)] struct Ret { x: String, diff --git a/dropshot/tests/fail/bad_endpoint7.stderr b/dropshot/tests/fail/bad_endpoint7.stderr index 632e09b4..063971ed 100644 --- a/dropshot/tests/fail/bad_endpoint7.stderr +++ b/dropshot/tests/fail/bad_endpoint7.stderr @@ -22,8 +22,8 @@ error[E0277]: the trait bound `Ret: serde::ser::Serialize` is not satisfied | ::: $WORKSPACE/dropshot/src/handler.rs | - | pub struct HttpResponseOk( - | --------- required by this bound in `HttpResponseOk` + | T: ExtractedParameter + Serialize + Send + Sync + 'static, + | --------- required by this bound in `HttpResponseOk` error[E0277]: the trait bound `Ret: serde::ser::Serialize` is not satisfied --> $DIR/bad_endpoint7.rs:24:5 @@ -36,8 +36,8 @@ error[E0277]: the trait bound `Ret: serde::ser::Serialize` is not satisfied | ::: $WORKSPACE/dropshot/src/handler.rs | - | pub struct HttpResponseOk( - | --------- required by this bound in `HttpResponseOk` + | T: ExtractedParameter + Serialize + Send + Sync + 'static, + | --------- required by this bound in `HttpResponseOk` error[E0277]: the trait bound `Ret: serde::ser::Serialize` is not satisfied --> $DIR/bad_endpoint7.rs:23:45 @@ -53,8 +53,8 @@ error[E0277]: the trait bound `Ret: serde::ser::Serialize` is not satisfied | ::: $WORKSPACE/dropshot/src/handler.rs | - | pub struct HttpResponseOk( - | --------- required by this bound in `HttpResponseOk` + | T: ExtractedParameter + Serialize + Send + Sync + 'static, + | --------- required by this bound in `HttpResponseOk` error[E0277]: the trait bound `fn(Arc) -> impl Future { for ApiEndpoint>::from::bad_endpoint}: dropshot::handler::HttpHandlerFunc<_, _>` is not satisfied --> $DIR/bad_endpoint7.rs:21:10 diff --git a/dropshot/tests/test_demo.rs b/dropshot/tests/test_demo.rs index 9f4684ab..90e9f3f6 100644 --- a/dropshot/tests/test_demo.rs +++ b/dropshot/tests/test_demo.rs @@ -19,6 +19,7 @@ use dropshot::endpoint; use dropshot::test_util::read_json; use dropshot::test_util::read_string; use dropshot::ApiDescription; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::Path; use dropshot::Query; @@ -29,7 +30,6 @@ use http::StatusCode; use hyper::Body; use hyper::Method; use hyper::Response; -use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::sync::Arc; @@ -528,7 +528,7 @@ async fn demo_handler_args_1( http_echo(&"demo_handler_args_1") } -#[derive(Serialize, Deserialize, JsonSchema)] +#[derive(Serialize, Deserialize, ExtractedParameter)] pub struct DemoQueryArgs { pub test1: String, pub test2: Option, @@ -544,7 +544,7 @@ async fn demo_handler_args_2query( http_echo(&query.into_inner()) } -#[derive(Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Serialize, Deserialize, ExtractedParameter)] pub struct DemoJsonBody { pub test1: String, pub test2: Option, @@ -560,7 +560,7 @@ async fn demo_handler_args_2json( http_echo(&json.into_inner()) } -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] pub struct DemoJsonAndQuery { pub query: DemoQueryArgs, pub json: DemoJsonBody, @@ -581,7 +581,7 @@ async fn demo_handler_args_3( http_echo(&combined) } -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] pub struct DemoPathString { pub test1: String, } @@ -596,7 +596,7 @@ async fn demo_handler_path_param_string( http_echo(&path_params.into_inner()) } -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] pub struct DemoPathUuid { pub test1: Uuid, } @@ -611,7 +611,7 @@ async fn demo_handler_path_param_uuid( http_echo(&path_params.into_inner()) } -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] pub struct DemoPathU32 { pub test1: u32, } @@ -626,7 +626,7 @@ async fn demo_handler_path_param_u32( http_echo(&path_params.into_inner()) } -#[derive(Deserialize, Serialize, JsonSchema)] +#[derive(Deserialize, Serialize, ExtractedParameter)] pub struct DemoPathImpossible { pub test1: String, } diff --git a/dropshot/tests/test_openapi.rs b/dropshot/tests/test_openapi.rs index 87073630..02bfd292 100644 --- a/dropshot/tests/test_openapi.rs +++ b/dropshot/tests/test_openapi.rs @@ -1,12 +1,11 @@ // Copyright 2020 Oxide Computer Company use dropshot::{ - endpoint, ApiDescription, HttpError, HttpResponseAccepted, - HttpResponseCreated, HttpResponseDeleted, HttpResponseOk, - HttpResponseUpdatedNoContent, PaginationParams, Path, Query, - RequestContext, ResultsPage, TypedBody, + endpoint, ApiDescription, ExtractedParameter, HttpError, + HttpResponseAccepted, HttpResponseCreated, HttpResponseDeleted, + HttpResponseOk, HttpResponseUpdatedNoContent, PaginationParams, Path, + Query, RequestContext, ResultsPage, TypedBody, }; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{io::Cursor, str::from_utf8, sync::Arc}; @@ -20,7 +19,7 @@ async fn handler1( Ok(HttpResponseOk(())) } -#[derive(Deserialize, JsonSchema)] +#[derive(Deserialize, ExtractedParameter)] #[allow(dead_code)] struct QueryArgs { _tomax: String, @@ -39,7 +38,7 @@ async fn handler2( Ok(HttpResponseUpdatedNoContent()) } -#[derive(Deserialize, JsonSchema)] +#[derive(Deserialize, ExtractedParameter)] #[allow(dead_code)] struct PathArgs { x: String, @@ -56,12 +55,12 @@ async fn handler3( Ok(HttpResponseDeleted()) } -#[derive(JsonSchema, Deserialize)] +#[derive(ExtractedParameter, Deserialize)] struct BodyParam { _x: String, } -#[derive(Serialize, JsonSchema)] +#[derive(Serialize, ExtractedParameter)] struct Response {} #[endpoint { @@ -89,18 +88,18 @@ async fn handler5( Ok(HttpResponseAccepted(())) } -#[derive(JsonSchema, Serialize)] +#[derive(ExtractedParameter, Serialize)] struct ResponseItem { word: String, } -#[derive(Deserialize, JsonSchema, Serialize)] +#[derive(Deserialize, ExtractedParameter, Serialize)] struct ExampleScanParams { #[serde(default)] a_number: u16, } -#[derive(Deserialize, JsonSchema, Serialize)] +#[derive(Deserialize, ExtractedParameter, Serialize)] struct ExamplePageSelector { scan: ExampleScanParams, last_seen: String, diff --git a/dropshot/tests/test_pagination.rs b/dropshot/tests/test_pagination.rs index 08634ffb..98ac1d44 100644 --- a/dropshot/tests/test_pagination.rs +++ b/dropshot/tests/test_pagination.rs @@ -16,6 +16,7 @@ use dropshot::ConfigLogging; use dropshot::ConfigLoggingIfExists; use dropshot::ConfigLoggingLevel; use dropshot::EmptyScanParams; +use dropshot::ExtractedParameter; use dropshot::HttpError; use dropshot::HttpResponseOk; use dropshot::PaginationOrder; @@ -29,7 +30,6 @@ use http::StatusCode; use hyper::Body; use hyper::Client; use hyper::Request; -use schemars::JsonSchema; use serde::de::DeserializeOwned; use serde::Deserialize; use serde::Serialize; @@ -150,7 +150,7 @@ where * * This is used for several resources below. */ -#[derive(Debug, Deserialize, JsonSchema, Serialize)] +#[derive(Debug, Deserialize, ExtractedParameter, Serialize)] struct IntegersPageSelector { last_seen: u16, } @@ -488,13 +488,13 @@ async fn api_with_extra_params( } /* TODO-coverage check generated OpenAPI spec */ -#[derive(Deserialize, JsonSchema)] +#[derive(Deserialize, ExtractedParameter)] struct ExtraQueryParams { debug: Option, } /* TODO-coverage check generated OpenAPI spec */ -#[derive(Debug, Deserialize, JsonSchema, Serialize)] +#[derive(Debug, Deserialize, ExtractedParameter, Serialize)] struct ExtraResultsPage { debug_was_set: bool, debug_value: bool, @@ -545,7 +545,7 @@ async fn test_paginate_extra_params() { * Test an endpoint that requires scan parameters. */ -#[derive(Deserialize, JsonSchema)] +#[derive(Deserialize, ExtractedParameter)] struct ReqScanParams { doit: bool, } @@ -645,13 +645,15 @@ fn make_word_list() -> BTreeSet { * The use of a structure here is kind of pointless except to exercise the case * of endpoints that return a custom structure. */ -#[derive(Debug, Deserialize, Clone, Eq, JsonSchema, PartialEq, Serialize)] +#[derive( + Debug, Deserialize, Clone, Eq, ExtractedParameter, PartialEq, Serialize, +)] struct DictionaryWord { word: String, length: usize, } -#[derive(Clone, Deserialize, JsonSchema, Serialize)] +#[derive(Clone, Deserialize, ExtractedParameter, Serialize)] struct DictionaryScanParams { #[serde(default = "ascending")] order: PaginationOrder, @@ -663,7 +665,7 @@ fn ascending() -> PaginationOrder { PaginationOrder::Ascending } -#[derive(Deserialize, JsonSchema, Serialize)] +#[derive(Deserialize, ExtractedParameter, Serialize)] struct DictionaryPageSelector { scan: DictionaryScanParams, last_seen: String,