From de6933ce478dfb57c444472971d8fe759c9d06b9 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 3 Dec 2024 10:58:05 -0800 Subject: [PATCH] reuse response schemas as well as body schemas --- dropshot/src/api_description.rs | 165 ++++-- dropshot/src/router.rs | 3 +- dropshot/tests/test_openapi.json | 480 +++--------------- .../test_openapi_custom_error_types.json | 86 ++-- ...penapi_custom_error_types_trait_based.json | 86 ++-- dropshot/tests/test_openapi_fuller.json | 480 +++--------------- dropshot/tests/test_openapi_overrides_v1.json | 30 +- dropshot/tests/test_openapi_overrides_v2.json | 30 +- dropshot/tests/test_pagination_schema.json | 30 +- dropshot/tests/test_versions_v0.9.0.json | 48 +- dropshot/tests/test_versions_v1.0.0.json | 30 +- dropshot/tests/test_versions_v1.1.0.json | 48 +- dropshot/tests/test_versions_v1.3.1.json | 48 +- dropshot/tests/test_versions_v1.4.0.json | 48 +- 14 files changed, 443 insertions(+), 1169 deletions(-) diff --git a/dropshot/src/api_description.rs b/dropshot/src/api_description.rs index d16b1a05..e493aca5 100644 --- a/dropshot/src/api_description.rs +++ b/dropshot/src/api_description.rs @@ -4,7 +4,6 @@ use crate::extractor::RequestExtractor; use crate::handler::HttpHandlerFunc; use crate::handler::HttpResponse; -use crate::handler::HttpResponseContent; use crate::handler::HttpResponseError; use crate::handler::HttpRouteHandler; use crate::handler::RouteHandler; @@ -53,7 +52,7 @@ pub struct ApiEndpoint { pub parameters: Vec, pub body_content_type: ApiEndpointBodyContentType, pub response: ApiEndpointResponse, - pub error: ApiEndpointErrorResponse, + pub error: Option, pub summary: Option, pub description: Option, pub tags: Vec, @@ -82,9 +81,7 @@ impl<'a, Context: ServerContext> ApiEndpoint { .expect("unsupported mime type"); let func_parameters = FuncParams::metadata(body_content_type.clone()); let response = ResponseType::response_metadata(); - let error = ApiEndpointErrorResponse { - schema: ::content_metadata(), - }; + let error = ApiEndpointErrorResponse::for_type::(); ApiEndpoint { operation_id, handler: HttpRouteHandler::new(handler), @@ -185,9 +182,7 @@ impl<'a> ApiEndpoint { .expect("unsupported mime type"); let func_parameters = FuncParams::metadata(body_content_type.clone()); let response = ::response_metadata(); - let error = ApiEndpointErrorResponse { - schema: ::content_metadata(), - }; + let error = ApiEndpointErrorResponse::for_type::(); let handler = StubRouteHandler::new_with_name(&operation_id); ApiEndpoint { operation_id, @@ -346,9 +341,17 @@ pub struct ApiEndpointResponse { } /// Metadata for an API endpoint's error response type. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ApiEndpointErrorResponse { - pub(crate) schema: Option, + schema: ApiSchemaGenerator, + type_name: &'static str, +} + +impl ApiEndpointErrorResponse { + fn for_type() -> Option { + let schema = T::content_metadata()?; + Some(Self { schema, type_name: std::any::type_name::() }) + } } /// Wrapper for both dynamically generated and pre-generated schemas. @@ -685,6 +688,28 @@ impl ApiDescription { let mut definitions = indexmap::IndexMap::::new(); + // A response object generated for an endpoint's error response. These + // are emitted in the top-level `components.responses` map in the + // OpenAPI document, so that multiple endpoints that return the same + // Rust error type can share error response schemas. + struct ErrorResponse { + response: openapiv3::Response, + name: String, + reference: openapiv3::ReferenceOr, + } + let mut error_responses = + indexmap::IndexMap::<&str, ErrorResponse>::new(); + // In the event that there are multiple Rust error types with the same + // name (e.g., both named 'Error'), we must disambiguate the name of the + // response by appending the number of occurances of that name. This is + // the mechanism as how `schemars` will disambiguate colliding schema + // names. However, we must implement our own version of this for + // response schemas, as we cannot simply use the response body's schema + // name: the body's schema may be a static, non-referenceable schema, so + // there isn't guaranteed to be a schema name we can reuse for the + // response object. + let mut error_response_names = HashMap::<&str, usize>::new(); + for (path, method, endpoint) in self.router.endpoints(Some(version)) { if !endpoint.visible { continue; @@ -939,43 +964,81 @@ impl ApiDescription { // If the endpoint defines an error type, emit that for // the 4xx and 5xx responses. - if let Some(ref schema) = endpoint.error.schema { - let error_schema = match schema { - ApiSchemaGenerator::Gen { ref name, ref schema } => { - j2oas_schema(Some(&name()), &schema(&mut generator)) - } - ApiSchemaGenerator::Static { - ref schema, - ref dependencies, - } => { - definitions.extend(dependencies.clone()); - j2oas_schema(None, &schema) - } - }; - let mut content = indexmap::IndexMap::new(); - content.insert( - CONTENT_TYPE_JSON.to_string(), - openapiv3::MediaType { - schema: Some(error_schema), - ..Default::default() - }, - ); - operation.responses.responses.insert( - openapiv3::StatusCode::Range(4), - openapiv3::ReferenceOr::Item(openapiv3::Response { - description: "client error".to_string(), - content: content.clone(), - ..Default::default() - }), - ); - operation.responses.responses.insert( - openapiv3::StatusCode::Range(5), - openapiv3::ReferenceOr::Item(openapiv3::Response { - description: "server error".to_string(), - content: content.clone(), - ..Default::default() - }), - ); + if let Some(ApiEndpointErrorResponse { ref schema, type_name }) = + endpoint.error + { + let ErrorResponse { reference, .. } = + // If a response object for this error type has already been + // generated, use that; otherwise, we'll generate it now. + error_responses.entry(type_name).or_insert_with(|| { + let error_schema = match schema { + ApiSchemaGenerator::Gen { + ref name, + ref schema, + } => j2oas_schema( + Some(&name()), + &schema(&mut generator), + ), + ApiSchemaGenerator::Static { + ref schema, + ref dependencies, + } => { + definitions.extend(dependencies.clone()); + j2oas_schema(None, &schema) + } + }; + + // If multiple distinct Rust error types with the same + // type name occur in the API, disambigate the response + // schemas by appending a number to each distinct error + // type. + // + // This is a bit ugly, but fortunately, it won't happen + // *too* often, and at least it's consistent with + // schemars' name disambiguation. + let type_name = type_name + .split("::") + .last() + .expect("type name must not be an empty string"); + let name = { + let num = error_response_names + .entry(type_name) + .and_modify(|num| *num += 1) + .or_insert(1); + if *num <= 1 { + type_name.to_string() + } else { + format!("{type_name}{num}") + } + }; + + let mut content = indexmap::IndexMap::new(); + content.insert( + CONTENT_TYPE_JSON.to_string(), + openapiv3::MediaType { + schema: Some(error_schema), + ..Default::default() + }, + ); + let response = openapiv3::Response { + description: type_name.to_string(), + content: content.clone(), + ..Default::default() + }; + let reference = openapiv3::ReferenceOr::Reference { + reference: format!("#/components/responses/{name}"), + }; + + ErrorResponse { name, reference, response } + }); + operation + .responses + .responses + .insert(openapiv3::StatusCode::Range(4), reference.clone()); + operation + .responses + .responses + .insert(openapiv3::StatusCode::Range(5), reference.clone()); } if let Some(code) = &endpoint.response.success { @@ -1014,6 +1077,14 @@ impl ApiDescription { } }); + // Generate error responses. + let responses = &mut components.responses; + for (_, ErrorResponse { name, response, .. }) in error_responses { + let prev = + responses.insert(name, openapiv3::ReferenceOr::Item(response)); + assert_eq!(prev, None, "error response names must be unique") + } + openapi } diff --git a/dropshot/src/router.rs b/dropshot/src/router.rs index 97946d67..9e643b43 100644 --- a/dropshot/src/router.rs +++ b/dropshot/src/router.rs @@ -828,7 +828,6 @@ mod test { use super::HttpRouter; use super::PathSegment; use crate::api_description::ApiEndpointBodyContentType; - use crate::api_description::ApiEndpointErrorResponse; use crate::api_description::ApiEndpointVersions; use crate::from_map::from_map; use crate::router::VariableValue; @@ -879,7 +878,7 @@ mod test { parameters: vec![], body_content_type: ApiEndpointBodyContentType::default(), response: ApiEndpointResponse::default(), - error: ApiEndpointErrorResponse::default(), + error: None, summary: None, description: None, tags: vec![], diff --git a/dropshot/tests/test_openapi.json b/dropshot/tests/test_openapi.json index 771c39c7..45945656 100644 --- a/dropshot/tests/test_openapi.json +++ b/dropshot/tests/test_openapi.json @@ -24,24 +24,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -57,24 +43,10 @@ "operationId": "handler8", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -97,24 +69,10 @@ "operationId": "handler9", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -147,24 +105,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -190,24 +134,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -233,24 +163,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -266,24 +182,10 @@ "operationId": "handler13", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -306,24 +208,10 @@ "operationId": "vzeroupper", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -384,24 +272,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -437,24 +311,10 @@ } }, "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" } }, "x-dropshot-websocket": {} @@ -468,24 +328,10 @@ "operationId": "handler18", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "", @@ -506,24 +352,10 @@ "operationId": "handler21", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "302": { "description": "redirect (found)", @@ -549,24 +381,10 @@ "operationId": "handler22", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "303": { "description": "redirect (see other)", @@ -592,24 +410,10 @@ "operationId": "handler23", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "307": { "description": "redirect (temporary redirect)", @@ -645,24 +449,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -685,24 +475,10 @@ "operationId": "handler24", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "307": { "description": "redirect (temporary redirect)", @@ -739,24 +515,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "successful deletion" @@ -783,24 +545,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -825,24 +573,10 @@ "operationId": "handler1", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -911,24 +645,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "202": { "description": "successfully enqueued operation", @@ -965,24 +685,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -1027,24 +733,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -1068,24 +760,10 @@ } }, "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" } } } @@ -1098,24 +776,10 @@ "operationId": "handler15", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -1142,24 +806,10 @@ "operationId": "handler19", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -1182,24 +832,10 @@ "operationId": "handler17", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated", @@ -1451,6 +1087,18 @@ "Foo": { "type": "string" } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } }, "tags": [ diff --git a/dropshot/tests/test_openapi_custom_error_types.json b/dropshot/tests/test_openapi_custom_error_types.json index 02374ae3..1862c2fb 100644 --- a/dropshot/tests/test_openapi_custom_error_types.json +++ b/dropshot/tests/test_openapi_custom_error_types.json @@ -10,24 +10,10 @@ "operationId": "dropshot_error_handler", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -61,24 +47,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EnumError" - } - } - } + "$ref": "#/components/responses/EnumError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EnumError" - } - } - } + "$ref": "#/components/responses/EnumError" }, "200": { "description": "successful operation", @@ -112,24 +84,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StructError" - } - } - } + "$ref": "#/components/responses/StructError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StructError" - } - } - } + "$ref": "#/components/responses/StructError" }, "200": { "description": "successful operation", @@ -258,6 +216,38 @@ "message" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "EnumError": { + "description": "EnumError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnumError" + } + } + } + }, + "StructError": { + "description": "StructError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StructError" + } + } + } + } } } } diff --git a/dropshot/tests/test_openapi_custom_error_types_trait_based.json b/dropshot/tests/test_openapi_custom_error_types_trait_based.json index 0f0c9bae..dbb01c75 100644 --- a/dropshot/tests/test_openapi_custom_error_types_trait_based.json +++ b/dropshot/tests/test_openapi_custom_error_types_trait_based.json @@ -10,24 +10,10 @@ "operationId": "dropshot_error", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -61,24 +47,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EnumError" - } - } - } + "$ref": "#/components/responses/EnumError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EnumError" - } - } - } + "$ref": "#/components/responses/EnumError" }, "200": { "description": "successful operation", @@ -112,24 +84,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StructError" - } - } - } + "$ref": "#/components/responses/StructError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StructError" - } - } - } + "$ref": "#/components/responses/StructError" }, "200": { "description": "successful operation", @@ -258,6 +216,38 @@ "message" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "EnumError": { + "description": "EnumError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EnumError" + } + } + } + }, + "StructError": { + "description": "StructError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StructError" + } + } + } + } } } } diff --git a/dropshot/tests/test_openapi_fuller.json b/dropshot/tests/test_openapi_fuller.json index 3948394f..924bdd02 100644 --- a/dropshot/tests/test_openapi_fuller.json +++ b/dropshot/tests/test_openapi_fuller.json @@ -32,24 +32,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -65,24 +51,10 @@ "operationId": "handler8", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -105,24 +77,10 @@ "operationId": "handler9", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -155,24 +113,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -198,24 +142,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -241,24 +171,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -274,24 +190,10 @@ "operationId": "handler13", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -314,24 +216,10 @@ "operationId": "vzeroupper", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -392,24 +280,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -445,24 +319,10 @@ } }, "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" } }, "x-dropshot-websocket": {} @@ -476,24 +336,10 @@ "operationId": "handler18", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "", @@ -514,24 +360,10 @@ "operationId": "handler21", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "302": { "description": "redirect (found)", @@ -557,24 +389,10 @@ "operationId": "handler22", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "303": { "description": "redirect (see other)", @@ -600,24 +418,10 @@ "operationId": "handler23", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "307": { "description": "redirect (temporary redirect)", @@ -653,24 +457,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -693,24 +483,10 @@ "operationId": "handler24", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "307": { "description": "redirect (temporary redirect)", @@ -747,24 +523,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "successful deletion" @@ -791,24 +553,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -833,24 +581,10 @@ "operationId": "handler1", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -919,24 +653,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "202": { "description": "successfully enqueued operation", @@ -973,24 +693,10 @@ }, "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "201": { "description": "successful creation", @@ -1035,24 +741,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated" @@ -1076,24 +768,10 @@ } }, "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" } } } @@ -1106,24 +784,10 @@ "operationId": "handler15", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -1150,24 +814,10 @@ "operationId": "handler19", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -1190,24 +840,10 @@ "operationId": "handler17", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "204": { "description": "resource updated", @@ -1459,6 +1095,18 @@ "Foo": { "type": "string" } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } }, "tags": [ diff --git a/dropshot/tests/test_openapi_overrides_v1.json b/dropshot/tests/test_openapi_overrides_v1.json index c0bff7bb..8b7d4d93 100644 --- a/dropshot/tests/test_openapi_overrides_v1.json +++ b/dropshot/tests/test_openapi_overrides_v1.json @@ -10,24 +10,10 @@ "operationId": "the_operation", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -75,6 +61,18 @@ "q" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_openapi_overrides_v2.json b/dropshot/tests/test_openapi_overrides_v2.json index 6b25f25f..5851c1ac 100644 --- a/dropshot/tests/test_openapi_overrides_v2.json +++ b/dropshot/tests/test_openapi_overrides_v2.json @@ -10,24 +10,10 @@ "operationId": "the_operation", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -75,6 +61,18 @@ "r" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_pagination_schema.json b/dropshot/tests/test_pagination_schema.json index 81fffcf3..082d2827 100644 --- a/dropshot/tests/test_pagination_schema.json +++ b/dropshot/tests/test_pagination_schema.json @@ -47,24 +47,10 @@ ], "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -144,6 +130,18 @@ "garbage-can" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_versions_v0.9.0.json b/dropshot/tests/test_versions_v0.9.0.json index 83c9dd48..658b8684 100644 --- a/dropshot/tests/test_versions_v0.9.0.json +++ b/dropshot/tests/test_versions_v0.9.0.json @@ -10,24 +10,10 @@ "operationId": "handler1", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -45,24 +31,10 @@ "operationId": "handler4", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -111,6 +83,18 @@ "request_id" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_versions_v1.0.0.json b/dropshot/tests/test_versions_v1.0.0.json index edccb42a..e44ff27c 100644 --- a/dropshot/tests/test_versions_v1.0.0.json +++ b/dropshot/tests/test_versions_v1.0.0.json @@ -10,24 +10,10 @@ "operationId": "handler4", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -65,6 +51,18 @@ "request_id" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_versions_v1.1.0.json b/dropshot/tests/test_versions_v1.1.0.json index 0105ed16..8d414929 100644 --- a/dropshot/tests/test_versions_v1.1.0.json +++ b/dropshot/tests/test_versions_v1.1.0.json @@ -10,24 +10,10 @@ "operationId": "handler2", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -46,24 +32,10 @@ "operationId": "handler4", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -101,6 +73,18 @@ "request_id" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_versions_v1.3.1.json b/dropshot/tests/test_versions_v1.3.1.json index f2105e79..a8624fdc 100644 --- a/dropshot/tests/test_versions_v1.3.1.json +++ b/dropshot/tests/test_versions_v1.3.1.json @@ -10,24 +10,10 @@ "operationId": "handler3", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -46,24 +32,10 @@ "operationId": "handler4", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -101,6 +73,18 @@ "request_id" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } } diff --git a/dropshot/tests/test_versions_v1.4.0.json b/dropshot/tests/test_versions_v1.4.0.json index 8e93db9a..e628a4a7 100644 --- a/dropshot/tests/test_versions_v1.4.0.json +++ b/dropshot/tests/test_versions_v1.4.0.json @@ -10,24 +10,10 @@ "operationId": "handler3", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -46,24 +32,10 @@ "operationId": "handler4", "responses": { "4XX": { - "description": "client error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "5XX": { - "description": "server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } + "$ref": "#/components/responses/HttpError" }, "200": { "description": "successful operation", @@ -101,6 +73,18 @@ "request_id" ] } + }, + "responses": { + "HttpError": { + "description": "HttpError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } } } }