Skip to content

Commit

Permalink
Add tuple support for component schema (#541)
Browse files Browse the repository at this point in the history
This commit adds support for tuple style object in OpenAPI schema.
Spec for tuples will be created according to https://serde.rs/json.html
and **Mixed Type Arrays** are used to define possible types.
https://swagger.io/docs/specification/data-models/data-types/

```rust
 #[derive(ToSchema)]
 struct Post {
     info: (String, i64, bool, Person)
 }
```
  • Loading branch information
juhaku authored Mar 23, 2023
1 parent b2e99a8 commit fed0226
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 7 deletions.
48 changes: 41 additions & 7 deletions utoipa-gen/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ fn is_default(container_rules: &Option<&SerdeContainer>, field_rule: &Option<&Se
/// or field attributes of struct.
fn get_deprecated(attributes: &[Attribute]) -> Option<Deprecated> {
attributes.iter().find_map(|attribute| {
if attribute.path.get_ident().map(|ident| *ident == "deprecated").unwrap_or(false) {
if attribute
.path
.get_ident()
.map(|ident| *ident == "deprecated")
.unwrap_or(false)
{
Some(Deprecated::True)
} else {
None
Expand Down Expand Up @@ -741,14 +746,43 @@ impl<'c> ComponentSchema {
}
}
}
// TODO support for tuple types
ValueType::Tuple => {
// Detect unit type ()
if type_tree.children.is_none() {
tokens.extend(quote! {
utoipa::openapi::schema::empty()
type_tree
.children
.as_ref()
.map(|children| {
let all_of = children.iter().fold(
quote! { utoipa::openapi::schema::AllOfBuilder::new() },
|mut all_of, child| {
let features = if child.is_option() {
Some(vec![Feature::Nullable(Nullable::new())])
} else {
None
};

let item = ComponentSchema::new(ComponentSchemaProps {
type_tree: child,
features,
description: None,
deprecated: None,
object_name,
});
all_of.extend(quote!( .item(#item) ));

all_of
},
);
quote! {
utoipa::openapi::schema::ArrayBuilder::new()
.items(#all_of)
#nullable
#description_stream
#deprecated_stream
}
})
};
.unwrap_or_else(|| quote!(utoipa::openapi::schema::empty()))
.to_tokens(tokens);
tokens.extend(features.to_token_stream());
}
}
}
Expand Down
81 changes: 81 additions & 0 deletions utoipa-gen/tests/schema_derive_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4232,3 +4232,84 @@ fn derive_schema_with_object_type_description() {
})
)
}

#[test]
fn derive_tuple_named_struct_field() {
#[derive(ToSchema)]
#[allow(unused)]
struct Person {
name: String,
}

let value = api_doc! {
struct Post {
info: (String, i64, bool, Person)
}
};
assert_json_eq!(
value,
json!({
"properties": {
"info": {
"items": {
"allOf": [
{
"type": "string"
},
{
"type": "integer",
"format": "int64",
},
{
"type": "boolean",
},
{
"$ref": "#/components/schemas/Person"
}
]
},
"type": "array"
}
},
"type": "object",
"required": ["info"]
})
)
}

#[test]
fn derive_nullable_tuple() {
let value = api_doc! {
struct Post {
/// This is description
#[deprecated]
info: Option<(String, i64)>
}
};

assert_json_eq!(
value,
json!({
"properties": {
"info": {
"items": {
"allOf": [
{
"type": "string"
},
{
"type": "integer",
"format": "int64",
},
]
},
"type": "array",
"nullable": true,
"deprecated": true,
"description": "This is description",
}
},
"type": "object",
})
)
}

0 comments on commit fed0226

Please sign in to comment.