Skip to content

Commit

Permalink
Implement automatic schema collection for requests (#1066)
Browse files Browse the repository at this point in the history
This PR implements functionality to recognize recursive schemas within
types implementing `ToSchema` trait by (derive). These schema references
will be collected to the single list of schemas which are added to the
schema automatically from their usage point.

If schema is registered at `schemas(MyType)` for `OpenApi` then the type
and it's schema references found recursively will be registered to the
`OpenApi`.

If the type is defined in `#[utoipa::path(request_body = ...)]` the
schema and it's recursively found schema references will be
automatically added to the schema when the handler is registered to the
`OpenApi`.

If the framework supports request body from http handler function
arguments (like `actix_web`, `axum`) then the schema will be added to
the `OpenApi` as well with recursively found schema references when the
handler is registered to the `OpenApi`.

This commit also refactors the parsing for `#[utoipa::path(request_body
= ...)]` Which enables the support for automatic schema reference
recognition and collection. This also comes with the possibility to only
add `request_body(content_type = "my/type")` without the schema if
wanted. More over from now on the `request_body` supports defining
multiple content objects allowing users to define multiple request body
content's like the responses support.

 ### Breaking changes

This `request_body` parsing is in over all breaking change and the
changed spec need be checked from the docs or tests. In short the
`content_type = ...` does not support anymore array syntax. E.g.
`content_type = [...]` is not possible anymore. Instead to support
multiple content types in request body on must define multiple content
objects similar to responses.
```text
 request_body(
    content(
        (Item = "content/type"),
        (Item = "content/type2"),
    )
 )
```

Example of supported syntax to demonstrate the automatic schema
collecting from `test_collect_schemas` handler when registered to the
`OpenApi`. Same way if `Person` was declared to `OpenApi` via
`schemas(Person)` then `Account` would also get registered.
```rust
 #[derive(ToSchema)]
 struct Account {
     id: i32,
 }

 #[derive(ToSchema)]
 struct Person {
     name: String,
     account: Account,
 }

 #[utoipa::path(
     post,
     request_body = Person,
     path = "/test-collect-schemas",
     responses(
         (status = 200, description = "success response")
     ),
 )]
 async fn test_collect_schemas(_body: Person) -> &'static str {
     ""
 }

 #[derive(OpenApi)]
 #[openapi(paths(test_collect_schemas))]
 struct ApiDoc;
```
  • Loading branch information
juhaku authored Sep 26, 2024
1 parent e0c5aa7 commit 5a06616
Show file tree
Hide file tree
Showing 25 changed files with 2,215 additions and 493 deletions.
332 changes: 240 additions & 92 deletions utoipa-gen/src/component.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions utoipa-gen/src/component/features/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ impl IntoParamsNames {
impl Parse for IntoParamsNames {
fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self> {
Ok(Self(
parse_utils::parse_punctuated_within_parenthesis::<LitStr>(input)?
parse_utils::parse_comma_separated_within_parenthesis::<LitStr>(input)?
.iter()
.map(LitStr::value)
.collect(),
Expand Down Expand Up @@ -877,7 +877,7 @@ impl Parse for Discriminator {
unexpected => {
return Err(Error::new(
property.span(),
&format!(
format!(
"unexpected identifier {}, expected any of: property_name, mapping",
unexpected
),
Expand Down
4 changes: 2 additions & 2 deletions utoipa-gen/src/component/into_params.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::borrow::Cow;

use proc_macro2::TokenStream;
use quote::quote;
use quote::{quote, ToTokens};
use syn::{
parse::Parse, punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Field,
Generics, Ident,
Expand Down Expand Up @@ -463,7 +463,7 @@ impl ToTokensDiagnostics for Param<'_> {
generics: self.generics,
},
})?;
let schema_tokens = crate::as_tokens_or_diagnostics!(&schema);
let schema_tokens = schema.to_token_stream();

tokens.extend(quote! { .schema(Some(#schema_tokens)).build() });
}
Expand Down
Loading

0 comments on commit 5a06616

Please sign in to comment.