diff --git a/utoipa-gen/CHANGELOG.md b/utoipa-gen/CHANGELOG.md index 154aad27..f18f8e0d 100644 --- a/utoipa-gen/CHANGELOG.md +++ b/utoipa-gen/CHANGELOG.md @@ -26,6 +26,7 @@ ### Fixed +* Fix `title` on unnamed struct and references (https://github.com/juhaku/utoipa/pull/1101) * Fix generic references (https://github.com/juhaku/utoipa/pull/1097) * Fix non generic root generic references (https://github.com/juhaku/utoipa/pull/1095) * Fix option wrapped tailing query parameters (https://github.com/juhaku/utoipa/pull/1089) diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs index 4c3b0a81..8d6feea9 100644 --- a/utoipa-gen/src/component.rs +++ b/utoipa-gen/src/component.rs @@ -901,6 +901,7 @@ impl ComponentSchema { let nullable: Option = pop_feature!(features => Feature::Nullable(_)).into_inner(); let default = pop_feature!(features => Feature::Default(_)); + let title = pop_feature!(features => Feature::Title(_)); let deprecated = pop_feature!(features => Feature::Deprecated(_)).try_to_token_stream()?; let child = type_tree @@ -980,10 +981,8 @@ impl ComponentSchema { tokens.extend(min_items.to_token_stream()) } - if let Some(default) = default { - tokens.extend(default.to_token_stream()) - } - + default.to_tokens(tokens)?; + title.to_tokens(tokens)?; example.to_tokens(tokens)?; xml.to_tokens(tokens)?; @@ -1092,10 +1091,12 @@ impl ComponentSchema { object_schema_reference.name = quote! { String::from(#name_tokens) }; - if is_inline { - let default = pop_feature!(features => Feature::Default(_)); - let default_tokens = as_tokens_or_diagnostics!(&default); + let default = pop_feature!(features => Feature::Default(_)); + let default_tokens = as_tokens_or_diagnostics!(&default); + let title = pop_feature!(features => Feature::Title(_)); + let title_tokens = as_tokens_or_diagnostics!(&title); + if is_inline { let items_tokens = if let Some(children) = &type_tree.children { schema_references.extend(Self::compose_child_references(children)); @@ -1112,11 +1113,12 @@ impl ComponentSchema { object_schema_reference.tokens = items_tokens.clone(); object_schema_reference.references = quote! { <#type_path as utoipa::__dev::SchemaReferences>::schemas(schemas) }; - let schema = if default.is_some() || nullable { + let schema = if default.is_some() || nullable || title.is_some() { quote_spanned! {type_path.span()=> utoipa::openapi::schema::AllOfBuilder::new() #nullable_item .item(#items_tokens) + #title_tokens #default_tokens } } else { @@ -1125,9 +1127,6 @@ impl ComponentSchema { schema.to_tokens(tokens); } else { - let default = pop_feature!(features => Feature::Default(_)); - let default_tokens = as_tokens_or_diagnostics!(&default); - let index = container.generics.get_generic_type_param_index(type_tree); // only set schema references for concrete non generic types if index.is_none() { @@ -1164,7 +1163,7 @@ impl ComponentSchema { // TODO: refs support `summary` field but currently there is no such field // on schemas more over there is no way to distinct the `summary` from // `description` of the ref. Should we consider supporting the summary? - let schema = if default.is_some() || nullable { + let schema = if default.is_some() || nullable || title.is_some() { composed_or_ref(quote_spanned! {type_path.span()=> utoipa::openapi::schema::AllOfBuilder::new() #nullable_item @@ -1172,6 +1171,7 @@ impl ComponentSchema { #description_stream .ref_location_from_schema_name(#name_tokens) ) + #title_tokens #default_tokens }) } else { diff --git a/utoipa-gen/tests/schema_derive_test.rs b/utoipa-gen/tests/schema_derive_test.rs index ba0e3cb3..87eea17a 100644 --- a/utoipa-gen/tests/schema_derive_test.rs +++ b/utoipa-gen/tests/schema_derive_test.rs @@ -5707,3 +5707,47 @@ fn derive_schema_with_ignored_field() { }) ) } + +#[test] +fn derive_schema_unnamed_title() { + #![allow(unused)] + + let value = api_doc! { + #[schema(title = "This is vec title")] + struct SchemaIgnoredField (Vec); + }; + + assert_json_eq!( + value, + json!({ + "title": "This is vec title", + "items": { + "type": "string" + }, + "type": "array" + }) + ); + + #[derive(ToSchema)] + enum UnnamedEnum { + One, + Two, + } + + let enum_value = api_doc! { + #[schema(title = "This is enum ref title")] + struct SchemaIgnoredField (UnnamedEnum); + }; + + assert_json_eq!( + enum_value, + json!({ + "title": "This is enum ref title", + "allOf": [ + { + "$ref": "#/components/schemas/UnnamedEnum" + } + ], + }) + ) +}