diff --git a/README.md b/README.md index 6f5ed154..154f98a5 100644 --- a/README.md +++ b/README.md @@ -168,24 +168,23 @@ For a complete example, see [the sample petstore](https://github.com/netwo-io/ap ### Feature flags -| name | description | extra dependencies | -|--------------------|--------------------------------------------------------------------------|-----------------------------------------------------------------| -| `query` (default) | Enables documenting `actix_web::web::Query` | | -| `actix` (default) | Enables documenting types from `actix` | | -| `lab_query` | Enables documenting `actix_web_lab::extract::Query` | [`actix-web-lab`](https://crates.io/crates/actix-web-lab) | -| `garde` | Enables input validation through `garde` | [`garde`](https://crates.io/crates/garde) | -| `actix-web-grants` | Enables support for `actix-web-grants` | [`actix-web-grants`](https://crates.io/crates/actix-web-grants) | -| `rapidoc` | Enables RapiDoc to expose the generated openapi file | | -| `redoc` | Enables Redoc to expose the generated openapi file | | -| `swagger-ui` | Enables Swagger UI to expose the generated openapi file | | -| `qs_query` | Enables documenting types from `serde_qs` | [`serde_qs`](https://crates.io/crates/serde-qs) | -| `chrono` | Enables documenting types from `chrono` | [`chrono`](https://crates.io/crates/chrono) | +| name | description | extra dependencies | +|-------------------|--------------------------------------------------------------------------|---------------------------------------------------------------| +| `query` (default) | Enables documenting `actix_web::web::Query` | | +| `actix` (default) | Enables documenting types from `actix` | | +| `lab_query` | Enables documenting `actix_web_lab::extract::Query` | [`actix-web-lab`](https://crates.io/crates/actix-web-lab) | +| `garde` | Enables input validation through `garde` | [`garde`](https://crates.io/crates/garde) | +| `rapidoc` | Enables RapiDoc to expose the generated openapi file | | +| `redoc` | Enables Redoc to expose the generated openapi file | | +| `swagger-ui` | Enables Swagger UI to expose the generated openapi file | | +| `qs_query` | Enables documenting types from `serde_qs` | [`serde_qs`](https://crates.io/crates/serde-qs) | +| `chrono` | Enables documenting types from `chrono` | [`chrono`](https://crates.io/crates/chrono) | | `ipnetwork` | Enables documenting types from `ipnetwork` | [`ipnetwork`](https://crates.io/crates/ipnetwork) | -| `multipart` | Enables documenting types from `actix-multipart` | [`actix-multipart`](https://crates.io/crates/actix-multipart) | -| `rust_decimal` | Enables documenting types from `rust_decimal` | [`rust_decimal`](https://crates.io/crates/rust-decimal) | -| `uuid` | Enables documenting types from `uuid` | [`uuid`](https://crates.io/crates/uuid) | -| `url` | Enables documenting types from `url` | [`url`](https://crates.io/crates/url) | -| `extras` | Enables `chrono`, `multipart`, `rust_decimal`, `uuid` and `url` features | All from previous features | +| `multipart` | Enables documenting types from `actix-multipart` | [`actix-multipart`](https://crates.io/crates/actix-multipart) | +| `rust_decimal` | Enables documenting types from `rust_decimal` | [`rust_decimal`](https://crates.io/crates/rust-decimal) | +| `uuid` | Enables documenting types from `uuid` | [`uuid`](https://crates.io/crates/uuid) | +| `url` | Enables documenting types from `url` | [`url`](https://crates.io/crates/url) | +| `extras` | Enables `chrono`, `multipart`, `rust_decimal`, `uuid` and `url` features | All from previous features | ### What's next diff --git a/apistos-core/src/api_component.rs b/apistos-core/src/api_component.rs index 8472ab93..59526597 100644 --- a/apistos-core/src/api_component.rs +++ b/apistos-core/src/api_component.rs @@ -1,11 +1,9 @@ -#[cfg(feature = "actix")] -use actix_web::Either; -use schemars::json_schema; -use serde_json::{json, Value}; use std::collections::BTreeMap; #[cfg(feature = "actix")] use std::future::Future; +use serde_json::{json, Value}; + use apistos_models::paths::{MediaType, Parameter, RequestBody, Response, Responses}; use apistos_models::reference_or::ReferenceOr; use apistos_models::security::SecurityScheme; @@ -198,124 +196,6 @@ where } } -impl ApiComponent for Either -where - T: ApiComponent, - E: ApiComponent, -{ - fn required() -> bool { - T::required() && E::required() - } - - fn child_schemas(oas_version: OpenApiVersion) -> Vec<(String, ReferenceOr)> { - let mut child_schemas = T::child_schemas(oas_version); - child_schemas.append(&mut E::child_schemas(oas_version)); - child_schemas - } - - fn raw_schema(oas_version: OpenApiVersion) -> Option> { - match (T::raw_schema(oas_version), E::raw_schema(oas_version)) { - (Some(raw_schema1), Some(raw_schema2)) => { - let raw_schema1 = match raw_schema1 { - ReferenceOr::Object(schema_obj) => schema_obj.into_inner(), - ReferenceOr::Reference { _ref } => json_schema!({ - "$ref": _ref - }), - }; - let raw_schema2 = match raw_schema2 { - ReferenceOr::Object(schema_obj) => schema_obj.into_inner(), - ReferenceOr::Reference { _ref } => json_schema!({ - "$ref": _ref - }), - }; - let schema = Schema::try_from(json!({ - "oneOf": [ - raw_schema1, - raw_schema2 - ] - })) - .map_err(|err| { - log::warn!("Error generating json schema: {err:?}"); - err - }) - .map(|sch| ApistosSchema::new(sch, oas_version)) - .unwrap_or_default() - .into(); - Some(schema) - } - (Some(raw_schema1), None) => Some(raw_schema1), - (None, Some(raw_schema2)) => Some(raw_schema2), - (None, None) => None, - } - } - - fn schema(oas_version: OpenApiVersion) -> Option<(String, ReferenceOr)> { - match (T::schema(oas_version), E::schema(oas_version)) { - (Some(schema1), Some(schema2)) => { - let (schema_name1, schema1) = schema1; - let schema1 = match schema1 { - ReferenceOr::Object(schema_obj) => schema_obj.into_inner(), - ReferenceOr::Reference { _ref } => json_schema!({ - "$ref": _ref - }), - }; - let (schema_name2, schema2) = schema2; - let schema2 = match schema2 { - ReferenceOr::Object(schema_obj) => schema_obj.into_inner(), - ReferenceOr::Reference { _ref } => json_schema!({ - "$ref": _ref - }), - }; - let schema = Schema::try_from(json!({ - "oneOf": [ - schema1, - schema2 - ] - })) - .map_err(|err| { - log::warn!("Error generating json schema: {err:?}"); - err - }) - .map(|sch| ApistosSchema::new(sch, oas_version)) - .unwrap_or_default() - .into(); - let schema_name = format!("Either{}Or{}", schema_name1, schema_name2); - Some((schema_name, schema)) - } - (Some(schema1), None) => Some(schema1), - (None, Some(schema2)) => Some(schema2), - (None, None) => None, - } - } - - fn error_responses(oas_version: OpenApiVersion) -> Vec<(String, Response)> { - let mut error_responses = T::error_responses(oas_version); - error_responses.append(&mut E::error_responses(oas_version)); - error_responses - } - - fn error_schemas(oas_version: OpenApiVersion) -> BTreeMap)> { - let mut error_schemas = E::error_schemas(oas_version); - error_schemas.append(&mut T::error_schemas(oas_version)); - error_schemas - } - - fn responses(oas_version: OpenApiVersion, content_type: Option) -> Option { - let responses = T::responses(oas_version, content_type.clone()); - match responses { - None => E::responses(oas_version, content_type), - Some(mut responses) => { - responses.responses.append( - &mut E::responses(oas_version, content_type) - .map(|r| r.responses) - .unwrap_or_default(), - ); - Some(responses) - } - } - } -} - #[cfg(feature = "actix")] impl ApiComponent for actix_web::web::Data { fn child_schemas(_: OpenApiVersion) -> Vec<(String, ReferenceOr)> { diff --git a/apistos-core/src/components/empty.rs b/apistos-core/src/components/empty.rs index 7396548b..4a661173 100644 --- a/apistos-core/src/components/empty.rs +++ b/apistos-core/src/components/empty.rs @@ -4,8 +4,6 @@ use actix_web::{HttpRequest, HttpResponse}; use apistos_models::reference_or::ReferenceOr; use apistos_models::ApistosSchema; -use crate::ApiComponent; - macro_rules! empty_component_impl { ($($ty:ty),+) => { $(impl ApiComponent for $ty { diff --git a/apistos-gen-test/src/tests/api_operation_oas_3_0.rs b/apistos-gen-test/src/tests/api_operation_oas_3_0.rs index 96c6cdfe..0757b57d 100644 --- a/apistos-gen-test/src/tests/api_operation_oas_3_0.rs +++ b/apistos-gen-test/src/tests/api_operation_oas_3_0.rs @@ -1461,105 +1461,3 @@ fn api_operation_root_vec() { }) ); } - -#[test] -fn api_operation_actix_web_grant() { - #[allow(clippy::unused_async)] - async fn extract(_req: &ServiceRequest) -> Result, Error> { - Ok(Default::default()) - } - - /// Add a new pet to the store - /// Add a new pet to the store - /// Plop - #[actix_web_grants::protect("ADMIN")] - #[api_operation(tag = "pet")] - pub(crate) async fn test( - _body: Json, - ) -> Result>, test_models::ErrorResponse> { - Ok(Json(vec![test_models::TestResult { id: 0 }])) - } - - let components = __openapi_test::components(OpenApiVersion::OAS3_0); - // only one component here because: error does not have schema and Test is used both for query and response - assert_eq!(components.len(), 1); - let components = serde_json::to_value(components).expect("Unable to serialize as Json"); - - let operation = __openapi_test::operation(OpenApiVersion::OAS3_0); - let operation = serde_json::to_value(operation).expect("Unable to serialize as Json"); - - assert_json_eq!( - components, - json!([ - { - "schemas": { - "Test": { - "properties": { - "test": { - "type": "string" - } - }, - "required": [ - "test" - ], - "title": "Test", - "type": "object" - }, - "TestResult": { - "properties": { - "id": { - "format": "uint32", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "id" - ], - "title": "TestResult", - "type": "object" - } - } - } - ]) - ); - assert_json_eq!( - operation, - json!({ - "deprecated": false, - "description": "Add a new pet to the store\\\nPlop", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Test" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TestResult" - } - } - } - }, - "description": "" - }, - "405": { - "description": "Invalid input" - } - }, - "summary": "Add a new pet to the store", - "tags": [ - "pet" - ] - }) - ); -} diff --git a/apistos-gen-test/src/tests/api_operation_oas_3_1.rs b/apistos-gen-test/src/tests/api_operation_oas_3_1.rs index 841c0b22..6d90a248 100644 --- a/apistos-gen-test/src/tests/api_operation_oas_3_1.rs +++ b/apistos-gen-test/src/tests/api_operation_oas_3_1.rs @@ -1,11 +1,9 @@ use actix_multipart::form::MultipartForm; -use actix_web::dev::ServiceRequest; use actix_web::http::header::ContentType; use actix_web::web::Json; -use actix_web::{Error, HttpResponse, Responder}; +use actix_web::{HttpResponse, Responder}; use assert_json_diff::assert_json_eq; use schemars::_serde_json::json; -use std::collections::HashSet; use uuid::Uuid; use apistos::actix::{AcceptedJson, CreatedJson, NoContent}; @@ -1322,104 +1320,3 @@ fn api_operation_root_vec() { }) ); } - -#[test] -fn api_operation_actix_web_grant() { - #[allow(clippy::unused_async)] - async fn extract(_req: &ServiceRequest) -> Result, Error> { - Ok(Default::default()) - } - - /// Add a new pet to the store - /// Add a new pet to the store - /// Plop - #[actix_web_grants::protect("ADMIN")] - #[api_operation(tag = "pet")] - pub(crate) async fn test( - _body: Json, - ) -> Result>, test_models::ErrorResponse> { - Ok(Json(vec![test_models::TestResult { id: 0 }])) - } - - let components = __openapi_test::components(OpenApiVersion::OAS3_1); - // only one component here because: error does not have schema and Test is used both for query and response - assert_eq!(components.len(), 1); - let components = serde_json::to_value(components).expect("Unable to serialize as Json"); - - let operation = __openapi_test::operation(OpenApiVersion::OAS3_1); - let operation = serde_json::to_value(operation).expect("Unable to serialize as Json"); - - assert_json_eq!( - components, - json!([ - { - "schemas": { - "TestResult": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "TestResult", - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "uint32", - "minimum": 0 - } - }, - "required": [ - "id" - ] - } - } - } - ]) - ); - assert_json_eq!( - operation, - json!({ - "tags": [ - "pet" - ], - "summary": "Add a new pet to the store", - "description": "Add a new pet to the store\\\nPlop", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Test", - "type": "object", - "properties": { - "test": { - "type": "string" - } - }, - "required": [ - "test" - ] - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TestResult" - } - } - } - } - }, - "405": { - "description": "Invalid input" - } - }, - "deprecated": false - }) - ); -} diff --git a/apistos/src/lib.rs b/apistos/src/lib.rs index 3f0d7312..06c3b179 100644 --- a/apistos/src/lib.rs +++ b/apistos/src/lib.rs @@ -117,24 +117,23 @@ //! //! # Feature flags //! -//! | name | description | extra dependencies | -//! |----------------|-----------------------------------------------------------------------------|----------------------------------------------------------------| -//! | `query` (default) | Enables documenting `actix_web::web::Query` | | -//! | `actix` (default) | Enables documenting types from `actix` | | -//! | `lab_query` | Enables documenting `actix_web_lab::extract::Query` | [`actix-web-lab`](https://crates.io/crates/actix-web-lab) | -//! | `garde` | Enables input validation through `garde` | [`garde`](https://crates.io/crates/garde) | -//! | `actix-web-grants`| Enables support for `actix-web-grants` | [`actix-web-grants`](https://crates.io/crates/actix-web-grants)| -//! | `qs_query` | Enables documenting types from `serde_qs` | [`serde_qs`](https://crates.io/crates/serde-qs) | -//! | `rapidoc` | Enables `RapiDoc` to expose the generated openapi file | | -//! | `redoc` | Enables `ReDoc` to expose the generated openapi file | | -//! | `swagger-ui` | Enables Swagger UI to expose the generated openapi file | | -//! | `chrono` | Enables documenting types from `chrono` | [`chrono`](https://crates.io/crates/chrono) | +//! | name | description | extra dependencies | +//! |----------------|-----------------------------------------------------------------------------|---------------------------------------------------------------| +//! | `query` (default) | Enables documenting `actix_web::web::Query` | | +//! | `actix` (default) | Enables documenting types from `actix` | | +//! | `lab_query` | Enables documenting `actix_web_lab::extract::Query` | [`actix-web-lab`](https://crates.io/crates/actix-web-lab) | +//! | `garde` | Enables input validation through `garde` | [`garde`](https://crates.io/crates/garde) | +//! | `qs_query` | Enables documenting types from `serde_qs` | [`serde_qs`](https://crates.io/crates/serde-qs) | +//! | `rapidoc` | Enables `RapiDoc` to expose the generated openapi file | | +//! | `redoc` | Enables `ReDoc` to expose the generated openapi file | | +//! | `swagger-ui` | Enables Swagger UI to expose the generated openapi file | | +//! | `chrono` | Enables documenting types from `chrono` | [`chrono`](https://crates.io/crates/chrono) | //! | `ipnetwork` | Enables documenting types from `ipnetwork` | [`ipnetwork`](https://crates.io/crates/ipnetwork) | -//! | `multipart` | Enables documenting types from `actix-multipart` | [`actix-multipart`](https://crates.io/crates/actix-multipart) | -//! | `rust_decimal` | Enables documenting types from `rust_decimal` | [`rust_decimal`](https://crates.io/crates/rust-decimal) | -//! | `uuid` | Enables documenting types from `uuid` | [`uuid`](https://crates.io/crates/uuid) | -//! | `url` | Enables documenting types from `url` | [`url`](https://crates.io/crates/url) | -//! | `extras` | Enables `chrono`, `multipart`, `rust_decimal`, `uuid` and `url` features | All from previous features | +//! | `multipart` | Enables documenting types from `actix-multipart` | [`actix-multipart`](https://crates.io/crates/actix-multipart) | +//! | `rust_decimal` | Enables documenting types from `rust_decimal` | [`rust_decimal`](https://crates.io/crates/rust-decimal) | +//! | `uuid` | Enables documenting types from `uuid` | [`uuid`](https://crates.io/crates/uuid) | +//! | `url` | Enables documenting types from `url` | [`url`](https://crates.io/crates/url) | +//! | `extras` | Enables `chrono`, `multipart`, `rust_decimal`, `uuid` and `url` features | All from previous features | //! //! It is possible to completely disable the documentation of `actix_web::web::Query`. This is useful when you want to enforce the use of `serde_qs::actix::QsQuery` in your project. To do so disable the default features. (Note: you might need to add `actix` feature as well) //!