utoipa_gen/lib.rs
1//! This is **private** utoipa codegen library and is not used alone.
2//!
3//! The library contains macro implementations for utoipa library. Content
4//! of the library documentation is available through **utoipa** library itself.
5//! Consider browsing via the **utoipa** crate so all links will work correctly.
6
7#![cfg_attr(doc_cfg, feature(doc_cfg))]
8#![warn(missing_docs)]
9#![warn(rustdoc::broken_intra_doc_links)]
10
11#[cfg(all(feature = "decimal", feature = "decimal_float"))]
12compile_error!("`decimal` and `decimal_float` are mutually exclusive feature flags");
13
14#[cfg(all(
15 feature = "actix_extras",
16 feature = "axum_extras",
17 feature = "rocket_extras"
18))]
19compile_error!(
20 "`actix_extras`, `axum_extras` and `rocket_extras` are mutually exclusive feature flags"
21);
22
23use std::{
24 borrow::{Borrow, Cow},
25 error::Error,
26 fmt::Display,
27 mem,
28 ops::Deref,
29};
30
31use component::schema::Schema;
32use doc_comment::CommentAttributes;
33
34use component::into_params::IntoParams;
35use ext::{PathOperationResolver, PathOperations, PathResolver};
36use openapi::OpenApi;
37use proc_macro::TokenStream;
38use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
39
40use proc_macro2::{Group, Ident, Punct, Span, TokenStream as TokenStream2};
41use syn::{
42 bracketed,
43 parse::{Parse, ParseStream},
44 punctuated::Punctuated,
45 token::Bracket,
46 DeriveInput, ExprPath, GenericParam, ItemFn, Lit, LitStr, Member, Token,
47};
48
49mod component;
50mod doc_comment;
51mod ext;
52mod openapi;
53mod path;
54mod schema_type;
55mod security_requirement;
56
57use crate::path::{Path, PathAttr};
58
59use self::{
60 component::{
61 features::{self, Feature},
62 ComponentSchema, ComponentSchemaProps, TypeTree,
63 },
64 openapi::parse_openapi_attrs,
65 path::response::derive::{IntoResponses, ToResponse},
66};
67
68#[cfg(feature = "config")]
69static CONFIG: once_cell::sync::Lazy<utoipa_config::Config> =
70 once_cell::sync::Lazy::new(utoipa_config::Config::read_from_file);
71
72#[proc_macro_derive(ToSchema, attributes(schema))]
73/// Generate reusable OpenAPI schema to be used
74/// together with [`OpenApi`][openapi_derive].
75///
76/// This is `#[derive]` implementation for [`ToSchema`][to_schema] trait. The macro accepts one
77/// `schema`
78/// attribute optionally which can be used to enhance generated documentation. The attribute can be placed
79/// at item level or field and variant levels in structs and enum.
80///
81/// You can use the Rust's own `#[deprecated]` attribute on any struct, enum or field to mark it as deprecated and it will
82/// reflect to the generated OpenAPI spec.
83///
84/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version but this is is not supported in
85/// OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
86/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
87///
88/// Doc comments on fields will resolve to field descriptions in generated OpenAPI doc. On struct
89/// level doc comments will resolve to object descriptions.
90///
91/// Schemas derived with `ToSchema` will be automatically collected from usage. In case of looping
92/// schema tree _`no_recursion`_ attribute must be used to break from recurring into infinite loop.
93/// See [more details from example][derive@ToSchema#examples]. All arguments of generic schemas
94/// must implement `ToSchema` trait.
95///
96/// ```rust
97/// /// This is a pet
98/// #[derive(utoipa::ToSchema)]
99/// struct Pet {
100/// /// Name for your pet
101/// name: String,
102/// }
103/// ```
104///
105/// # Named Field Struct Optional Configuration Options for `#[schema(...)]`
106///
107/// * `description = ...` Can be literal string or Rust expression e.g. _`const`_ reference or
108/// `include_str!(...)` statement. This can be used to override **default** description what is
109/// resolved from doc comments of the type.
110/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
111/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
112/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
113/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
114/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to Structs.
115/// * `title = ...` Literal string value. Can be used to define title for struct in OpenAPI
116/// document. Some OpenAPI code generation libraries also use this field as a name for the
117/// struct.
118/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all fields
119/// of the structs accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_ are defined
120/// __serde__ will take precedence.
121/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
122/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
123/// OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
124/// with `utoipa` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
125/// or in [`utoipa::path(...)`][path_macro] macro.
126/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
127/// See [Generic schemas section](#generic-schemas) below for more details.
128/// * `default` Can be used to populate default values on all fields using the struct's
129/// [`Default`] implementation.
130/// * `deprecated` Can be used to mark all fields as deprecated in the generated OpenAPI spec but
131/// not in the code. If you'd like to mark the fields as deprecated in the code as well use
132/// Rust's own `#[deprecated]` attribute instead.
133/// * `max_properties = ...` Can be used to define maximum number of properties this struct can
134/// contain. Value must be a number.
135/// * `min_properties = ...` Can be used to define minimum number of properties this struct can
136/// contain. Value must be a number.
137///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
138/// `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
139/// recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**. On
140/// struct level the _`no_recursion`_ rule will be applied to all of its fields.
141///
142/// ## Named Fields Optional Configuration Options for `#[schema(...)]`
143///
144/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
145/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
146/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
147/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
148/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
149/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
150/// an open value as a string. By default the format is derived from the type of the property
151/// according OpenApi spec.
152/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
153/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
154/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to named fields.
155/// See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
156/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
157/// This is useful in cases where the default type does not correspond to the actual type e.g. when
158/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
159/// The value can be any Rust type what normally could be used to serialize to JSON, or either virtual type _`Object`_
160/// or _`Value`_.
161/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
162/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
163/// * `inline` If the type of this field implements [`ToSchema`][to_schema], then the schema definition
164/// will be inlined. **warning:** Don't use this for recursive data types!
165///
166/// **Note!**<br>Using `inline` with generic arguments might lead to incorrect spec generation.
167/// This is due to the fact that during compilation we cannot know how to treat the generic
168/// argument and there is difference whether it is a primitive type or another generic type.
169/// * `required = ...` Can be used to enforce required status for the field. [See
170/// rules][derive@ToSchema#field-nullability-and-required-rules]
171/// * `nullable` Defines property is nullable (note this is different to non-required).
172/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename field
173/// accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
174/// precedence.
175/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
176/// division will result an `integer`. Value must be strictly above _`0`_.
177/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
178/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
179/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
180/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
181/// * `max_length = ...` Can be used to define maximum length for `string` types.
182/// * `min_length = ...` Can be used to define minimum length for `string` types.
183/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
184/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
185/// be non-negative integer.
186/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
187/// be non-negative integer.
188/// * `schema_with = ...` Use _`schema`_ created by provided function reference instead of the
189/// default derived _`schema`_. The function must match to `fn() -> Into<RefOr<Schema>>`. It does
190/// not accept arguments and must return anything that can be converted into `RefOr<Schema>`.
191/// * `additional_properties = ...` Can be used to define free form types for maps such as
192/// [`HashMap`](std::collections::HashMap) and [`BTreeMap`](std::collections::BTreeMap).
193/// Free form type enables use of arbitrary types within map values.
194/// Supports formats _`additional_properties`_ and _`additional_properties = true`_.
195/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
196/// not in the code. If you'd like to mark the field as deprecated in the code as well use
197/// Rust's own `#[deprecated]` attribute instead.
198/// * `content_encoding = ...` Can be used to define content encoding used for underlying schema object.
199/// See [`Object::content_encoding`][schema_object_encoding]
200/// * `content_media_type = ...` Can be used to define MIME type of a string for underlying schema object.
201/// See [`Object::content_media_type`][schema_object_media_type]
202///* `ignore` or `ignore = ...` Can be used to skip the field from being serialized to OpenAPI schema. It accepts either a literal `bool` value
203/// or a path to a function that returns `bool` (`Fn() -> bool`).
204///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
205/// `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
206/// recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**.
207///
208/// #### Field nullability and required rules
209///
210/// Field is considered _`required`_ if
211/// * it is not `Option` field
212/// * and it does not have _`skip_serializing_if`_ property
213/// * and it does not have _`serde_with`_ _[`double_option`](https://docs.rs/serde_with/latest/serde_with/rust/double_option/index.html)_
214/// * and it does not have default value provided with serde _`default`_
215/// attribute
216///
217/// Field is considered _`nullable`_ when field type is _`Option`_.
218///
219/// ## Xml attribute Configuration Options
220///
221/// * `xml(name = "...")` Will set name for property or type.
222/// * `xml(namespace = "...")` Will set namespace for xml element which needs to be valid uri.
223/// * `xml(prefix = "...")` Will set prefix for name.
224/// * `xml(attribute)` Will translate property to xml attribute instead of xml element.
225/// * `xml(wrapped)` Will make wrapped xml element.
226/// * `xml(wrapped(name = "wrap_name"))` Will override the wrapper elements name.
227///
228/// See [`Xml`][xml] for more details.
229///
230/// # Unnamed Field Struct Optional Configuration Options for `#[schema(...)]`
231///
232/// * `description = ...` Can be literal string or Rust expression e.g. [_`const`_][const] reference or
233/// `include_str!(...)` statement. This can be used to override **default** description what is
234/// resolved from doc comments of the type.
235/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
236/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
237/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
238/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
239/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_. If no value
240/// is specified, and the struct has only one field, the field's default value in the schema will be
241/// set from the struct's [`Default`] implementation.
242/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
243/// an open value as a string. By default the format is derived from the type of the property
244/// according OpenApi spec.
245/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
246/// This is useful in cases where the default type does not correspond to the actual type e.g. when
247/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
248/// The value can be any Rust type what normally could be used to serialize to JSON or either virtual type _`Object`_
249/// or _`Value`_.
250/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
251/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
252/// * `title = ...` Literal string value. Can be used to define title for struct in OpenAPI
253/// document. Some OpenAPI code generation libraries also use this field as a name for the
254/// struct.
255/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
256/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
257/// OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
258/// with `utoipa` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
259/// or in [`utoipa::path(...)`][path_macro] macro.
260/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
261/// See [Generic schemas section](#generic-schemas) below for more details.
262/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
263/// not in the code. If you'd like to mark the field as deprecated in the code as well use
264/// Rust's own `#[deprecated]` attribute instead.
265/// * `content_encoding = ...` Can be used to define content encoding used for underlying schema object.
266/// See [`Object::content_encoding`][schema_object_encoding]
267/// * `content_media_type = ...` Can be used to define MIME type of a string for underlying schema object.
268/// See [`Object::content_media_type`][schema_object_media_type]
269///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
270/// `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
271/// recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**.
272///
273/// # Enum Optional Configuration Options for `#[schema(...)]`
274///
275/// ## Plain Enum having only `Unit` variants Optional Configuration Options for `#[schema(...)]`
276///
277/// * `description = ...` Can be literal string or Rust expression e.g. [_`const`_][const] reference or
278/// `include_str!(...)` statement. This can be used to override **default** description what is
279/// resolved from doc comments of the type.
280/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
281/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
282/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
283/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
284/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
285/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
286/// document. Some OpenAPI code generation libraries also use this field as a name for the
287/// enum.
288/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
289/// variants of the enum accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
290/// are defined __serde__ will take precedence.
291/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
292/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
293/// OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
294/// with `utoipa` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
295/// or in [`utoipa::path(...)`][path_macro] macro.
296/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
297/// See [Generic schemas section](#generic-schemas) below for more details.
298/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
299/// not in the code. If you'd like to mark the enum as deprecated in the code as well use
300/// Rust's own `#[deprecated]` attribute instead.
301///
302/// ### Plain Enum Variant Optional Configuration Options for `#[schema(...)]`
303///
304/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
305/// accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
306/// precedence. **Note!** [`Repr enum`][macro@ToSchema#repr-attribute-support] variant does not
307/// support _`rename`_.
308///
309/// ## Mixed Enum Optional Configuration Options for `#[schema(...)]`
310///
311/// * `description = ...` Can be literal string or Rust expression e.g. [_`const`_][const] reference or
312/// `include_str!(...)` statement. This can be used to override **default** description what is
313/// resolved from doc comments of the type.
314/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
315/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
316/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
317/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
318/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
319/// document. Some OpenAPI code generation libraries also use this field as a name for the
320/// enum.
321/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
322/// variants of the enum accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
323/// are defined __serde__ will take precedence.
324/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
325/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
326/// OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
327/// with `utoipa` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
328/// or in [`utoipa::path(...)`][path_macro] macro.
329/// * `bound = ...` Can be used to override default trait bounds on generated `impl`s.
330/// See [Generic schemas section](#generic-schemas) below for more details.
331/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
332/// not in the code. If you'd like to mark the enum as deprecated in the code as well use
333/// Rust's own `#[deprecated]` attribute instead.
334/// * `discriminator = ...` or `discriminator(...)` Can be used to define OpenAPI discriminator
335/// field for enums with single unnamed _`ToSchema`_ reference field. See the [discriminator
336/// syntax][derive@ToSchema#schemadiscriminator-syntax].
337///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
338/// `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
339/// recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**. On
340/// enum level the _`no_recursion`_ rule will be applied to all of its variants.
341///
342/// ### `#[schema(discriminator)]` syntax
343///
344/// Discriminator can **only** be used with enums having **`#[serde(untagged)]`** attribute and
345/// each variant must have only one unnamed field schema reference to type implementing
346/// _`ToSchema`_.
347///
348/// **Simple form `discriminator = ...`**
349///
350/// Can be literal string or expression e.g. [_`const`_][const] reference. It can be defined as
351/// _`discriminator = "value"`_ where the assigned value is the
352/// discriminator field that must exists in each variant referencing schema.
353///
354/// **Complex form `discriminator(...)`**
355///
356/// * `property_name = ...` Can be literal string or expression e.g. [_`const`_][const] reference.
357/// * mapping `key` Can be literal string or expression e.g. [_`const`_][const] reference.
358/// * mapping `value` Can be literal string or expression e.g. [_`const`_][const] reference.
359///
360/// Additionally discriminator can be defined with custom mappings as show below. The _`mapping`_
361/// values defines _**key = value**_ pairs where _**key**_ is the expected value for _**property_name**_ field
362/// and _**value**_ is schema to map.
363/// ```text
364/// discriminator(property_name = "my_field", mapping(
365/// ("value" = "#/components/schemas/Schema1"),
366/// ("value2" = "#/components/schemas/Schema2")
367/// ))
368/// ```
369///
370/// ### Mixed Enum Named Field Variant Optional Configuration Options for `#[serde(schema)]`
371///
372/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
373/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
374/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
375/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
376/// * `title = ...` Literal string value. Can be used to define title for enum variant in OpenAPI
377/// document. Some OpenAPI code generation libraries also use this field as a name for the
378/// enum.
379/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to Structs.
380/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
381/// accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
382/// precedence.
383/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
384/// variant fields accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
385/// are defined __serde__ will take precedence.
386/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
387/// not in the code. If you'd like to mark the enum as deprecated in the code as well use
388/// Rust's own `#[deprecated]` attribute instead.
389/// * `max_properties = ...` Can be used to define maximum number of properties this struct can
390/// contain. Value must be a number.
391/// * `min_properties = ...` Can be used to define minimum number of properties this struct can
392/// contain. Value must be a number.
393///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
394/// `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
395/// recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**. On
396/// named field variant level the _`no_recursion`_ rule will be applied to all of its fields.
397///
398/// ## Mixed Enum Unnamed Field Variant Optional Configuration Options for `#[serde(schema)]`
399///
400/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
401/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
402/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
403/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
404/// * `default = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
405/// * `title = ...` Literal string value. Can be used to define title for enum variant in OpenAPI
406/// document. Some OpenAPI code generation libraries also use this field as a name for the
407/// struct.
408/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
409/// accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
410/// precedence.
411/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
412/// an open value as a string. By default the format is derived from the type of the property
413/// according OpenApi spec.
414/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
415/// This is useful in cases where the default type does not correspond to the actual type e.g. when
416/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
417/// The value can be any Rust type what normally could be used to serialize to JSON or either virtual type _`Object`_
418/// or _`Value`_.
419/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
420/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
421/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
422/// not in the code. If you'd like to mark the field as deprecated in the code as well use
423/// Rust's own `#[deprecated]` attribute instead.
424///* `no_recursion` Is used to break from recursion in case of looping schema tree e.g. `Pet` ->
425/// `Owner` -> `Pet`. _`no_recursion`_ attribute must be used within `Ower` type not to allow
426/// recurring into `Pet`. Failing to do so will cause infinite loop and runtime **panic**.
427///
428/// #### Mixed Enum Unnamed Field Variant's Field Configuration Options
429///
430/// * `inline` If the type of this field implements [`ToSchema`][to_schema], then the schema definition
431/// will be inlined. **warning:** Don't use this for recursive data types!
432///
433/// **Note!**<br>Using `inline` with generic arguments might lead to incorrect spec generation.
434/// This is due to the fact that during compilation we cannot know how to treat the generic
435/// argument and there is difference whether it is a primitive type or another generic type.
436///
437/// _**Inline unnamed field variant schemas.**_
438/// ```rust
439/// # use utoipa::ToSchema;
440/// # #[derive(ToSchema)]
441/// # enum Number {
442/// # One,
443/// # }
444/// #
445/// # #[derive(ToSchema)]
446/// # enum Color {
447/// # Spade,
448/// # }
449/// #[derive(ToSchema)]
450/// enum Card {
451/// Number(#[schema(inline)] Number),
452/// Color(#[schema(inline)] Color),
453/// }
454/// ```
455///
456/// ## Mixed Enum Unit Field Variant Optional Configuration Options for `#[serde(schema)]`
457///
458/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
459/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
460/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
461/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
462/// * `title = ...` Literal string value. Can be used to define title for enum variant in OpenAPI
463/// document. Some OpenAPI code generation libraries also use this field as a name for the
464/// struct.
465/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename variant
466/// accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
467/// precedence.
468/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
469/// not in the code. If you'd like to mark the field as deprecated in the code as well use
470/// Rust's own `#[deprecated]` attribute instead.
471///
472/// # Partial `#[serde(...)]` attributes support
473///
474/// ToSchema derive has partial support for [serde attributes]. These supported attributes will reflect to the
475/// generated OpenAPI doc. For example if _`#[serde(skip)]`_ is defined the attribute will not show up in the OpenAPI spec at all since it will not never
476/// be serialized anyway. Similarly the _`rename`_ and _`rename_all`_ will reflect to the generated OpenAPI doc.
477///
478/// * `rename_all = "..."` Supported at the container level.
479/// * `rename = "..."` Supported **only** at the field or variant level.
480/// * `skip = "..."` Supported **only** at the field or variant level.
481/// * `skip_serializing = "..."` Supported **only** at the field or variant level.
482/// * `skip_deserializing = "..."` Supported **only** at the field or variant level.
483/// * `skip_serializing_if = "..."` Supported **only** at the field level.
484/// * `with = ...` Supported **only at field level.**
485/// * `tag = "..."` Supported at the container level.
486/// * `content = "..."` Supported at the container level, allows [adjacently-tagged enums](https://serde.rs/enum-representations.html#adjacently-tagged).
487/// This attribute requires that a `tag` is present, otherwise serde will trigger a compile-time
488/// failure.
489/// * `untagged` Supported at the container level. Allows [untagged
490/// enum representation](https://serde.rs/enum-representations.html#untagged).
491/// * `default` Supported at the container level and field level according to [serde attributes].
492/// * `deny_unknown_fields` Supported at the container level.
493/// * `flatten` Supported at the field level.
494///
495/// Other _`serde`_ attributes works as is but does not have any effect on the generated OpenAPI doc.
496///
497/// **Note!** `tag` attribute has some limitations like it cannot be used with **tuple types**. See more at
498/// [enum representation docs](https://serde.rs/enum-representations.html).
499///
500/// **Note!** `with` attribute is used in tandem with [serde_with](https://github.com/jonasbb/serde_with) to recognize
501/// _[`double_option`](https://docs.rs/serde_with/latest/serde_with/rust/double_option/index.html)_ from **field value**.
502/// _`double_option`_ is **only** supported attribute from _`serde_with`_ crate.
503///
504/// ```rust
505/// # use serde::Serialize;
506/// # use utoipa::ToSchema;
507/// #[derive(Serialize, ToSchema)]
508/// struct Foo(String);
509///
510/// #[derive(Serialize, ToSchema)]
511/// #[serde(rename_all = "camelCase")]
512/// enum Bar {
513/// UnitValue,
514/// #[serde(rename_all = "camelCase")]
515/// NamedFields {
516/// #[serde(rename = "id")]
517/// named_id: &'static str,
518/// name_list: Option<Vec<String>>
519/// },
520/// UnnamedFields(Foo),
521/// #[serde(skip)]
522/// SkipMe,
523/// }
524/// ```
525///
526/// _**Add custom `tag` to change JSON representation to be internally tagged.**_
527/// ```rust
528/// # use serde::Serialize;
529/// # use utoipa::ToSchema;
530/// #[derive(Serialize, ToSchema)]
531/// struct Foo(String);
532///
533/// #[derive(Serialize, ToSchema)]
534/// #[serde(tag = "tag")]
535/// enum Bar {
536/// UnitValue,
537/// NamedFields {
538/// id: &'static str,
539/// names: Option<Vec<String>>
540/// },
541/// }
542/// ```
543///
544/// _**Add serde `default` attribute for MyValue struct. Similarly `default` could be added to
545/// individual fields as well. If `default` is given the field's affected will be treated
546/// as optional.**_
547/// ```rust
548/// #[derive(utoipa::ToSchema, serde::Deserialize, Default)]
549/// #[serde(default)]
550/// struct MyValue {
551/// field: String
552/// }
553/// ```
554///
555/// # `#[repr(...)]` attribute support
556///
557/// [Serde repr](https://github.com/dtolnay/serde-repr) allows field-less enums be represented by
558/// their numeric value.
559///
560/// * `repr(u*)` for unsigned integer.
561/// * `repr(i*)` for signed integer.
562///
563/// **Supported schema attributes**
564///
565/// * `example = ...` Can be any value e.g. literal, method reference or _`json!(...)`_.
566/// **Deprecated since OpenAPI 3.0, using `examples` is preferred instead.**
567/// * `examples(..., ...)` Comma separated list defining multiple _`examples`_ for the schema. Each
568/// _`example`_ Can be any value e.g. literal, method reference or _`json!(...)`_.
569/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
570/// document. Some OpenAPI code generation libraries also use this field as a name for the
571/// struct.
572/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
573/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
574/// OpenAPI spec as _`path.to.Pet`_. This same name will be used throughout the OpenAPI generated
575/// with `utoipa` when the type is being referenced in [`OpenApi`][openapi_derive] derive macro
576/// or in [`utoipa::path(...)`][path_macro] macro.
577///
578/// _**Create enum with numeric values.**_
579/// ```rust
580/// # use utoipa::ToSchema;
581/// #[derive(ToSchema)]
582/// #[repr(u8)]
583/// #[schema(default = default_value, example = 2)]
584/// enum Mode {
585/// One = 1,
586/// Two,
587/// }
588///
589/// fn default_value() -> u8 {
590/// 1
591/// }
592/// ```
593///
594/// _**You can use `skip` and `tag` attributes from serde.**_
595/// ```rust
596/// # use utoipa::ToSchema;
597/// #[derive(ToSchema, serde::Serialize)]
598/// #[repr(i8)]
599/// #[serde(tag = "code")]
600/// enum ExitCode {
601/// Error = -1,
602/// #[serde(skip)]
603/// Unknown = 0,
604/// Ok = 1,
605/// }
606/// ```
607///
608/// # Generic schemas
609///
610/// Utoipa supports full set of deeply nested generics as shown below. The type will implement
611/// [`ToSchema`][to_schema] if and only if all the generic types implement `ToSchema` by default.
612/// That is in Rust `impl<T> ToSchema for MyType<T> where T: Schema { ... }`.
613/// You can also specify `bound = ...` on the item to override the default auto bounds.
614///
615/// The _`as = ...`_ attribute is used to define the prefixed or alternative name for the component
616/// in question. This same name will be used throughout the OpenAPI generated with `utoipa` when
617/// the type is being referenced in [`OpenApi`][openapi_derive] derive macro or in [`utoipa::path(...)`][path_macro] macro.
618///
619/// ```rust
620/// # use utoipa::ToSchema;
621/// # use std::borrow::Cow;
622/// #[derive(ToSchema)]
623/// #[schema(as = path::MyType<T>)]
624/// struct Type<T> {
625/// t: T,
626/// }
627///
628/// #[derive(ToSchema)]
629/// struct Person<'p, T: Sized, P> {
630/// id: usize,
631/// name: Option<Cow<'p, str>>,
632/// field: T,
633/// t: P,
634/// }
635///
636/// #[derive(ToSchema)]
637/// #[schema(as = path::to::PageList)]
638/// struct Page<T> {
639/// total: usize,
640/// page: usize,
641/// pages: usize,
642/// items: Vec<T>,
643/// }
644///
645/// #[derive(ToSchema)]
646/// #[schema(as = path::to::Element<T>)]
647/// enum E<T> {
648/// One(T),
649/// Many(Vec<T>),
650/// }
651/// ```
652/// When generic types are registered to the `OpenApi` the full type declaration must be provided.
653/// See the full example in test [schema_generics.rs](https://github.com/juhaku/utoipa/blob/master/utoipa-gen/tests/schema_generics.rs)
654///
655/// # Examples
656///
657/// _**Simple example of a Pet with descriptions and object level example.**_
658/// ```rust
659/// # use utoipa::ToSchema;
660/// /// This is a pet.
661/// #[derive(ToSchema)]
662/// #[schema(example = json!({"name": "bob the cat", "id": 0}))]
663/// struct Pet {
664/// /// Unique id of a pet.
665/// id: u64,
666/// /// Name of a pet.
667/// name: String,
668/// /// Age of a pet if known.
669/// age: Option<i32>,
670/// }
671/// ```
672///
673/// _**The `schema` attribute can also be placed at field level as follows.**_
674/// ```rust
675/// # use utoipa::ToSchema;
676/// #[derive(ToSchema)]
677/// struct Pet {
678/// #[schema(example = 1, default = 0)]
679/// id: u64,
680/// name: String,
681/// age: Option<i32>,
682/// }
683/// ```
684///
685/// _**You can also use method reference for attribute values.**_
686/// ```rust
687/// # use utoipa::ToSchema;
688/// #[derive(ToSchema)]
689/// struct Pet {
690/// #[schema(example = u64::default, default = u64::default)]
691/// id: u64,
692/// #[schema(default = default_name)]
693/// name: String,
694/// age: Option<i32>,
695/// }
696///
697/// fn default_name() -> String {
698/// "bob".to_string()
699/// }
700/// ```
701///
702/// _**For enums and unnamed field structs you can define `schema` at type level.**_
703/// ```rust
704/// # use utoipa::ToSchema;
705/// #[derive(ToSchema)]
706/// #[schema(example = "Bus")]
707/// enum VehicleType {
708/// Rocket, Car, Bus, Submarine
709/// }
710/// ```
711///
712/// _**Also you write mixed enum combining all above types.**_
713/// ```rust
714/// # use utoipa::ToSchema;
715/// #[derive(ToSchema)]
716/// enum ErrorResponse {
717/// InvalidCredentials,
718/// #[schema(default = String::default, example = "Pet not found")]
719/// NotFound(String),
720/// System {
721/// #[schema(example = "Unknown system failure")]
722/// details: String,
723/// }
724/// }
725/// ```
726///
727/// _**It is possible to specify the title of each variant to help generators create named structures.**_
728/// ```rust
729/// # use utoipa::ToSchema;
730/// #[derive(ToSchema)]
731/// enum ErrorResponse {
732/// #[schema(title = "InvalidCredentials")]
733/// InvalidCredentials,
734/// #[schema(title = "NotFound")]
735/// NotFound(String),
736/// }
737/// ```
738///
739/// _**Use `xml` attribute to manipulate xml output.**_
740/// ```rust
741/// # use utoipa::ToSchema;
742/// #[derive(ToSchema)]
743/// #[schema(xml(name = "user", prefix = "u", namespace = "https://user.xml.schema.test"))]
744/// struct User {
745/// #[schema(xml(attribute, prefix = "u"))]
746/// id: i64,
747/// #[schema(xml(name = "user_name", prefix = "u"))]
748/// username: String,
749/// #[schema(xml(wrapped(name = "linkList"), name = "link"))]
750/// links: Vec<String>,
751/// #[schema(xml(wrapped, name = "photo_url"))]
752/// photos_urls: Vec<String>
753/// }
754/// ```
755///
756/// _**Use of Rust's own `#[deprecated]` attribute will reflect to generated OpenAPI spec.**_
757/// ```rust
758/// # use utoipa::ToSchema;
759/// #[derive(ToSchema)]
760/// #[deprecated]
761/// struct User {
762/// id: i64,
763/// username: String,
764/// links: Vec<String>,
765/// #[deprecated]
766/// photos_urls: Vec<String>
767/// }
768/// ```
769///
770/// _**Enforce type being used in OpenAPI spec to [`String`] with `value_type` and set format to octet stream
771/// with [`SchemaFormat::KnownFormat(KnownFormat::Binary)`][binary].**_
772/// ```rust
773/// # use utoipa::ToSchema;
774/// #[derive(ToSchema)]
775/// struct Post {
776/// id: i32,
777/// #[schema(value_type = String, format = Binary)]
778/// value: Vec<u8>,
779/// }
780/// ```
781///
782/// _**Enforce type being used in OpenAPI spec to [`String`] with `value_type` option.**_
783/// ```rust
784/// # use utoipa::ToSchema;
785/// #[derive(ToSchema)]
786/// #[schema(value_type = String)]
787/// struct Value(i64);
788/// ```
789///
790/// _**Override the `Bar` reference with a `custom::NewBar` reference.**_
791/// ```rust
792/// # use utoipa::ToSchema;
793/// # mod custom {
794/// # #[derive(utoipa::ToSchema)]
795/// # pub struct NewBar;
796/// # }
797/// #
798/// # struct Bar;
799/// #[derive(ToSchema)]
800/// struct Value {
801/// #[schema(value_type = custom::NewBar)]
802/// field: Bar,
803/// };
804/// ```
805///
806/// _**Use a virtual `Object` type to render generic `object` _(`type: object`)_ in OpenAPI spec.**_
807/// ```rust
808/// # use utoipa::ToSchema;
809/// # mod custom {
810/// # struct NewBar;
811/// # }
812/// #
813/// # struct Bar;
814/// #[derive(ToSchema)]
815/// struct Value {
816/// #[schema(value_type = Object)]
817/// field: Bar,
818/// };
819/// ```
820/// More examples for _`value_type`_ in [`IntoParams` derive docs][into_params].
821///
822/// _**Serde `rename` / `rename_all` will take precedence over schema `rename` / `rename_all`.**_
823/// ```rust
824/// #[derive(utoipa::ToSchema, serde::Deserialize)]
825/// #[serde(rename_all = "lowercase")]
826/// #[schema(rename_all = "UPPERCASE")]
827/// enum Random {
828/// #[serde(rename = "string_value")]
829/// #[schema(rename = "custom_value")]
830/// String(String),
831///
832/// Number {
833/// id: i32,
834/// }
835/// }
836/// ```
837///
838/// _**Add `title` to the enum.**_
839/// ```rust
840/// #[derive(utoipa::ToSchema)]
841/// #[schema(title = "UserType")]
842/// enum UserType {
843/// Admin,
844/// Moderator,
845/// User,
846/// }
847/// ```
848///
849/// _**Example with validation attributes.**_
850/// ```rust
851/// #[derive(utoipa::ToSchema)]
852/// struct Item {
853/// #[schema(maximum = 10, minimum = 5, multiple_of = 2.5)]
854/// id: i32,
855/// #[schema(max_length = 10, min_length = 5, pattern = "[a-z]*")]
856/// value: String,
857/// #[schema(max_items = 5, min_items = 1)]
858/// items: Vec<String>,
859/// }
860/// ````
861///
862/// _**Use `schema_with` to manually implement schema for a field.**_
863/// ```rust
864/// # use utoipa::openapi::schema::{Object, ObjectBuilder};
865/// fn custom_type() -> Object {
866/// ObjectBuilder::new()
867/// .schema_type(utoipa::openapi::schema::Type::String)
868/// .format(Some(utoipa::openapi::SchemaFormat::Custom(
869/// "email".to_string(),
870/// )))
871/// .description(Some("this is the description"))
872/// .build()
873/// }
874///
875/// #[derive(utoipa::ToSchema)]
876/// struct Value {
877/// #[schema(schema_with = custom_type)]
878/// id: String,
879/// }
880/// ```
881///
882/// _**Use `as` attribute to change the name and the path of the schema in the generated OpenAPI
883/// spec.**_
884/// ```rust
885/// #[derive(utoipa::ToSchema)]
886/// #[schema(as = api::models::person::Person)]
887/// struct Person {
888/// name: String,
889/// }
890/// ```
891///
892/// _**Use `bound` attribute to override the default impl bounds.**_
893///
894/// `bound = ...` accepts a string containing zero or more where-predicates separated by comma, as
895/// the similar syntax to [`serde(bound = ...)`](https://serde.rs/container-attrs.html#bound).
896/// If `bound = ...` exists, the default auto bounds (requiring all generic types to implement
897/// `ToSchema`) will not be applied anymore, and only the specified predicates are added to the
898/// `where` clause of generated `impl` blocks.
899///
900/// ```rust
901/// // Override the default bounds to only require `T: ToSchema`, ignoring unused `U`.
902/// #[derive(utoipa::ToSchema, serde::Serialize)]
903/// #[schema(bound = "T: utoipa::ToSchema")]
904/// struct Partial<T, U> {
905/// used_in_api: T,
906/// #[serde(skip)]
907/// not_in_api: std::marker::PhantomData<U>,
908/// }
909///
910/// // Just remove the auto-bounds. So we got `Unused<T>: ToSchema` for any `T`.
911/// #[derive(utoipa::ToSchema, serde::Serialize)]
912/// #[schema(bound = "")]
913/// struct Unused<T> {
914/// #[serde(skip)]
915/// _marker: std::marker::PhantomData<T>,
916/// }
917/// ```
918///
919/// _**Use `no_recursion` attribute to break from looping schema tree e.g. `Pet` -> `Owner` ->
920/// `Pet`.**_
921///
922/// `no_recursion` attribute can be provided on named field of a struct, on unnamed struct or unnamed
923/// enum variant. It must be provided in case of looping schema tree in order to stop recursion.
924/// Failing to do so will cause runtime **panic**.
925/// ```rust
926/// # use utoipa::ToSchema;
927/// #
928/// #[derive(ToSchema)]
929/// pub struct Pet {
930/// name: String,
931/// owner: Owner,
932/// }
933///
934/// #[derive(ToSchema)]
935/// pub struct Owner {
936/// name: String,
937/// #[schema(no_recursion)]
938/// pets: Vec<Pet>,
939/// }
940/// ```
941///
942/// [to_schema]: trait.ToSchema.html
943/// [known_format]: openapi/schema/enum.KnownFormat.html
944/// [binary]: openapi/schema/enum.KnownFormat.html#variant.Binary
945/// [xml]: openapi/xml/struct.Xml.html
946/// [into_params]: derive.IntoParams.html
947/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
948/// [serde attributes]: https://serde.rs/attributes.html
949/// [discriminator]: openapi/schema/struct.Discriminator.html
950/// [enum_schema]: derive.ToSchema.html#enum-optional-configuration-options-for-schema
951/// [openapi_derive]: derive.OpenApi.html
952/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
953/// [schema_object_encoding]: openapi/schema/struct.Object.html#structfield.content_encoding
954/// [schema_object_media_type]: openapi/schema/struct.Object.html#structfield.content_media_type
955/// [path_macro]: macro@path
956/// [const]: https://doc.rust-lang.org/std/keyword.const.html
957pub fn derive_to_schema(input: TokenStream) -> TokenStream {
958 let DeriveInput {
959 attrs,
960 ident,
961 data,
962 generics,
963 ..
964 } = syn::parse_macro_input!(input);
965
966 Schema::new(&data, &attrs, &ident, &generics)
967 .as_ref()
968 .map_or_else(Diagnostics::to_token_stream, Schema::to_token_stream)
969 .into()
970}
971
972#[proc_macro_attribute]
973/// Path attribute macro implements OpenAPI path for the decorated function.
974///
975/// This is a `#[derive]` implementation for [`Path`][path] trait. Macro accepts set of attributes that can
976/// be used to configure and override default values what are resolved automatically.
977///
978/// You can use the Rust's own `#[deprecated]` attribute on functions to mark it as deprecated and it will
979/// reflect to the generated OpenAPI spec. Only **parameters** has a special **deprecated** attribute to define them as deprecated.
980///
981/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version but this is is not supported in
982/// OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
983/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
984///
985/// Doc comment at decorated function will be used for _`description`_ and _`summary`_ of the path.
986/// First line of the doc comment will be used as the _`summary`_ while the remaining lines will be
987/// used as _`description`_.
988/// ```rust
989/// /// This is a summary of the operation
990/// ///
991/// /// The rest of the doc comment will be included to operation description.
992/// #[utoipa::path(get, path = "/operation")]
993/// fn operation() {}
994/// ```
995///
996/// # Path Attributes
997///
998/// * `operation` _**Must be first parameter!**_ Accepted values are known HTTP operations such as
999/// _`get, post, put, delete, head, options, patch, trace`_.
1000///
1001/// * `method(get, head, ...)` Http methods for the operation. This allows defining multiple
1002/// HTTP methods at once for single operation. Either _`operation`_ or _`method(...)`_ _**must be
1003/// provided.**_
1004///
1005/// * `path = "..."` Must be OpenAPI format compatible str with arguments within curly braces. E.g _`{id}`_
1006///
1007/// * `impl_for = ...` Optional type to implement the [`Path`][path] trait. By default a new type
1008/// is used for the implementation.
1009///
1010/// * `operation_id = ...` Unique operation id for the endpoint. By default this is mapped to function name.
1011/// The operation_id can be any valid expression (e.g. string literals, macro invocations, variables) so long
1012/// as its result can be converted to a `String` using `String::from`.
1013///
1014/// * `context_path = "..."` Can add optional scope for **path**. The **context_path** will be prepended to beginning of **path**.
1015/// This is particularly useful when **path** does not contain the full path to the endpoint. For example if web framework
1016/// allows operation to be defined under some context path or scope which does not reflect to the resolved path then this
1017/// **context_path** can become handy to alter the path.
1018///
1019/// * `tag = "..."` Can be used to group operations. Operations with same tag are grouped together. By default
1020/// this is derived from the module path of the handler that is given to [`OpenApi`][openapi].
1021///
1022/// * `tags = ["tag1", ...]` Can be used to group operations. Operations with same tag are grouped
1023/// together. Tags attribute can be used to add additional _tags_ for the operation. If both
1024/// _`tag`_ and _`tags`_ are provided then they will be combined to a single _`tags`_ array.
1025///
1026/// * `request_body = ... | request_body(...)` Defining request body indicates that the request is expecting request body within
1027/// the performed request.
1028///
1029/// * `responses(...)` Slice of responses the endpoint is going to possibly return to the caller.
1030///
1031/// * `params(...)` Slice of params that the endpoint accepts.
1032///
1033/// * `security(...)` List of [`SecurityRequirement`][security]s local to the path operation.
1034///
1035/// * `summary = ...` Allows overriding summary of the path. Value can be literal string or valid
1036/// rust expression e.g. `include_str!(...)` or `const` reference.
1037///
1038/// * `description = ...` Allows overriding description of the path. Value can be literal string or valid
1039/// rust expression e.g. `include_str!(...)` or `const` reference.
1040///
1041/// * `extensions(...)` List of extensions local to the path operation.
1042///
1043/// # Request Body Attributes
1044///
1045/// ## Simple format definition by `request_body = ...`
1046/// * _`request_body = Type`_, _`request_body = inline(Type)`_ or _`request_body = ref("...")`_.
1047/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1048/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1049/// [`ToSchema`][to_schema] types. _`ref("./external.json")`_ can be used to reference external
1050/// json file for body schema. **Note!** Utoipa does **not** guarantee that free form _`ref`_ is accessible via
1051/// OpenAPI doc or Swagger UI, users are responsible for making these guarantees.
1052///
1053/// ## Advanced format definition by `request_body(...)`
1054///
1055/// With advanced format the request body supports defining either one or multiple request bodies by `content` attribute.
1056///
1057/// ### Common request body attributes
1058///
1059/// * `description = "..."` Define the description for the request body object as str.
1060///
1061/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
1062/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
1063///
1064/// * `examples(...)` Define multiple examples for single request body. This attribute is mutually
1065/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
1066/// This has same syntax as _`examples(...)`_ in [Response Attributes](#response-attributes)
1067/// _examples(...)_
1068///
1069/// ### Single request body content
1070///
1071/// * `content = ...` Can be _`content = Type`_, _`content = inline(Type)`_ or _`content = ref("...")`_. The
1072/// given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec
1073/// or Map etc. With _`inline(...)`_ the schema will be inlined instead of a referenced
1074/// which is the default for [`ToSchema`][to_schema] types. _`ref("./external.json")`_
1075/// can be used to reference external json file for body schema. **Note!** Utoipa does **not** guarantee
1076/// that free form _`ref`_ is accessible via OpenAPI doc or Swagger UI, users are responsible for making
1077/// these guarantees.
1078///
1079/// * `content_type = "..."` Can be used to override the default behavior
1080/// of auto resolving the content type from the `content` attribute. If defined the value should be valid
1081/// content type such as _`application/json`_ . By default the content type is _`text/plain`_
1082/// for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
1083/// for struct and mixed enum types.
1084///
1085/// _**Example of single request body definitions.**_
1086/// ```text
1087/// request_body(content = String, description = "Xml as string request", content_type = "text/xml"),
1088/// request_body(content_type = "application/json"),
1089/// request_body = Pet,
1090/// request_body = Option<[Pet]>,
1091/// ```
1092///
1093/// ### Multiple request body content
1094///
1095/// * `content(...)` Can be tuple of content tuples according to format below.
1096/// ```text
1097/// ( schema )
1098/// ( schema = "content/type", example = ..., examples(..., ...) )
1099/// ( "content/type", ),
1100/// ( "content/type", example = ..., examples(..., ...) )
1101/// ```
1102///
1103/// First argument of content tuple is _`schema`_, which is optional as long as either _`schema`_
1104/// or _`content/type`_ is defined. The _`schema`_ and _`content/type`_ is separated with equals
1105/// (=) sign. Optionally content tuple supports defining _`example`_ and _`examples`_ arguments. See
1106/// [common request body attributes][macro@path#common-request-body-attributes]
1107///
1108/// _**Example of multiple request body definitions.**_
1109///
1110/// ```text
1111/// // guess the content type for Pet and Pet2
1112/// request_body(description = "Common description",
1113/// content(
1114/// (Pet),
1115/// (Pet2)
1116/// )
1117/// ),
1118/// // define explicit content types
1119/// request_body(description = "Common description",
1120/// content(
1121/// (Pet = "application/json", examples(..., ...), example = ...),
1122/// (Pet2 = "text/xml", examples(..., ...), example = ...)
1123/// )
1124/// ),
1125/// // omit schema and accept arbitrary content types
1126/// request_body(description = "Common description",
1127/// content(
1128/// ("application/json"),
1129/// ("text/xml", examples(..., ...), example = ...)
1130/// )
1131/// ),
1132/// ```
1133///
1134/// # Response Attributes
1135///
1136/// * `status = ...` Is either a valid http status code integer. E.g. _`200`_ or a string value representing
1137/// a range such as _`"4XX"`_ or `"default"` or a valid _`http::status::StatusCode`_.
1138/// _`StatusCode`_ can either be use path to the status code or _status code_ constant directly.
1139///
1140/// * `description = "..."` Define description for the response as str.
1141///
1142/// * `body = ...` Optional response body object type. When left empty response does not expect to send any
1143/// response body. Can be _`body = Type`_, _`body = inline(Type)`_, or _`body = ref("...")`_.
1144/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1145/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1146/// [`ToSchema`][to_schema] types. _`ref("./external.json")`_
1147/// can be used to reference external json file for body schema. **Note!** Utoipa does **not** guarantee
1148/// that free form _`ref`_ is accessible via OpenAPI doc or Swagger UI, users are responsible for making
1149/// these guarantees.
1150///
1151/// * `content_type = "..."` Can be used to override the default behavior
1152/// of auto resolving the content type from the `body` attribute. If defined the value should be valid
1153/// content type such as _`application/json`_ . By default the content type is _`text/plain`_
1154/// for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
1155/// for struct and mixed enum types.
1156///
1157/// * `headers(...)` Slice of response headers that are returned back to a caller.
1158///
1159/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
1160/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
1161///
1162/// * `response = ...` Type what implements [`ToResponse`][to_response_trait] trait. This can alternatively be used to
1163/// define response attributes. _`response`_ attribute cannot co-exist with other than _`status`_ attribute.
1164///
1165/// * `content((...), (...))` Can be used to define multiple return types for single response status. Supports same syntax as
1166/// [multiple request body content][`macro@path#multiple-request-body-content`].
1167///
1168/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
1169/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
1170///
1171/// * `links(...)` Define a map of operations links that can be followed from the response.
1172///
1173/// ## Response `examples(...)` syntax
1174///
1175/// * `name = ...` This is first attribute and value must be literal string.
1176/// * `summary = ...` Short description of example. Value must be literal string.
1177/// * `description = ...` Long description of example. Attribute supports markdown for rich text
1178/// representation. Value must be literal string.
1179/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
1180/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
1181/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
1182/// the _`value`_ attribute. Value must be literal string.
1183///
1184/// _**Example of example definition.**_
1185/// ```text
1186/// ("John" = (summary = "This is John", value = json!({"name": "John"})))
1187/// ```
1188///
1189/// ## Response `links(...)` syntax
1190///
1191/// * `operation_ref = ...` Define a relative or absolute URI reference to an OAS operation. This field is
1192/// mutually exclusive of the _`operation_id`_ field, and **must** point to an [Operation Object][operation].
1193/// Value can be be [`str`] or an expression such as [`include_str!`][include_str] or static
1194/// [`const`][const] reference.
1195///
1196/// * `operation_id = ...` Define the name of an existing, resolvable OAS operation, as defined with a unique
1197/// _`operation_id`_. This field is mutually exclusive of the _`operation_ref`_ field.
1198/// Value can be be [`str`] or an expression such as [`include_str!`][include_str] or static
1199/// [`const`][const] reference.
1200///
1201/// * `parameters(...)` A map representing parameters to pass to an operation as specified with _`operation_id`_
1202/// or identified by _`operation_ref`_. The key is parameter name to be used and value can
1203/// be any value supported by JSON or an [expression][expression] e.g. `$path.id`
1204/// * `name = ...` Define name for the parameter.
1205/// Value can be be [`str`] or an expression such as [`include_str!`][include_str] or static
1206/// [`const`][const] reference.
1207/// * `value` = Any value that can be supported by JSON or an [expression][expression].
1208///
1209/// _**Example of parameters syntax:**_
1210/// ```text
1211/// parameters(
1212/// ("name" = value),
1213/// ("name" = value)
1214/// ),
1215/// ```
1216///
1217/// * `request_body = ...` Define a literal value or an [expression][expression] to be used as request body when
1218/// operation is called
1219///
1220/// * `description = ...` Define description of the link. Value supports Markdown syntax.Value can be be [`str`] or
1221/// an expression such as [`include_str!`][include_str] or static [`const`][const] reference.
1222///
1223/// * `server(...)` Define [Server][server] object to be used by the target operation. See
1224/// [server syntax][server_derive_syntax]
1225///
1226/// **Links syntax example:** See the full example below in [examples](#examples).
1227/// ```text
1228/// responses(
1229/// (status = 200, description = "success response",
1230/// links(
1231/// ("link_name" = (
1232/// operation_id = "test_links",
1233/// parameters(("key" = "value"), ("json_value" = json!(1))),
1234/// request_body = "this is body",
1235/// server(url = "http://localhost")
1236/// ))
1237/// )
1238/// )
1239/// )
1240/// ```
1241///
1242/// **Minimal response format:**
1243/// ```text
1244/// responses(
1245/// (status = 200, description = "success response"),
1246/// (status = 404, description = "resource missing"),
1247/// (status = "5XX", description = "server error"),
1248/// (status = StatusCode::INTERNAL_SERVER_ERROR, description = "internal server error"),
1249/// (status = IM_A_TEAPOT, description = "happy easter")
1250/// )
1251/// ```
1252///
1253/// **More complete Response:**
1254/// ```text
1255/// responses(
1256/// (status = 200, description = "Success response", body = Pet, content_type = "application/json",
1257/// headers(...),
1258/// example = json!({"id": 1, "name": "bob the cat"})
1259/// )
1260/// )
1261/// ```
1262///
1263/// **Multiple response return types with _`content(...)`_ attribute:**
1264///
1265/// _**Define multiple response return types for single response status with their own example.**_
1266/// ```text
1267/// responses(
1268/// (status = 200, content(
1269/// (User = "application/vnd.user.v1+json", example = json!(User {id: "id".to_string()})),
1270/// (User2 = "application/vnd.user.v2+json", example = json!(User2 {id: 2}))
1271/// )
1272/// )
1273/// )
1274/// ```
1275///
1276/// ### Using `ToResponse` for reusable responses
1277///
1278/// _**`ReusableResponse` must be a type that implements [`ToResponse`][to_response_trait].**_
1279/// ```text
1280/// responses(
1281/// (status = 200, response = ReusableResponse)
1282/// )
1283/// ```
1284///
1285/// _**[`ToResponse`][to_response_trait] can also be inlined to the responses map.**_
1286/// ```text
1287/// responses(
1288/// (status = 200, response = inline(ReusableResponse))
1289/// )
1290/// ```
1291///
1292/// ## Responses from `IntoResponses`
1293///
1294/// _**Responses for a path can be specified with one or more types that implement
1295/// [`IntoResponses`][into_responses_trait].**_
1296/// ```text
1297/// responses(MyResponse)
1298/// ```
1299///
1300/// # Response Header Attributes
1301///
1302/// * `name` Name of the header. E.g. _`x-csrf-token`_
1303///
1304/// * `type` Additional type of the header value. Can be `Type` or `inline(Type)`.
1305/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1306/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1307/// [`ToSchema`][to_schema] types. **Reminder!** It's up to the user to use valid type for the
1308/// response header.
1309///
1310/// * `description = "..."` Can be used to define optional description for the response header as str.
1311///
1312/// **Header supported formats:**
1313///
1314/// ```text
1315/// ("x-csrf-token"),
1316/// ("x-csrf-token" = String, description = "New csrf token"),
1317/// ```
1318///
1319/// # Params Attributes
1320///
1321/// The list of attributes inside the `params(...)` attribute can take two forms: [Tuples](#tuples) or [IntoParams
1322/// Type](#intoparams-type).
1323///
1324/// ## Tuples
1325///
1326/// In the tuples format, parameters are specified using the following attributes inside a list of
1327/// tuples separated by commas:
1328///
1329/// * `name` _**Must be the first argument**_. Define the name for parameter.
1330///
1331/// * `parameter_type` Define possible type for the parameter. Can be `Type` or `inline(Type)`.
1332/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
1333/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
1334/// [`ToSchema`][to_schema] types. Parameter type is placed after `name` with
1335/// equals sign E.g. _`"id" = string`_
1336///
1337/// * `in` _**Must be placed after name or parameter_type**_. Define the place of the parameter.
1338/// This must be one of the variants of [`openapi::path::ParameterIn`][in_enum].
1339/// E.g. _`Path, Query, Header, Cookie`_
1340///
1341/// * `deprecated` Define whether the parameter is deprecated or not. Can optionally be defined
1342/// with explicit `bool` value as _`deprecated = bool`_.
1343///
1344/// * `description = "..."` Define possible description for the parameter as str.
1345///
1346/// * `style = ...` Defines how parameters are serialized by [`ParameterStyle`][style]. Default values are based on _`in`_ attribute.
1347///
1348/// * `explode` Defines whether new _`parameter=value`_ is created for each parameter within _`object`_ or _`array`_.
1349///
1350/// * `allow_reserved` Defines whether reserved characters _`:/?#[]@!$&'()*+,;=`_ is allowed within value.
1351///
1352/// * `example = ...` Can method reference or _`json!(...)`_. Given example
1353/// will override any example in underlying parameter type.
1354///
1355/// * `extensions(...)` List of extensions local to the parameter
1356///
1357/// ##### Parameter type attributes
1358///
1359/// These attributes supported when _`parameter_type`_ is present. Either by manually providing one
1360/// or otherwise resolved e.g from path macro argument when _`actix_extras`_ crate feature is
1361/// enabled.
1362///
1363/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
1364/// an open value as a string. By default the format is derived from the type of the property
1365/// according OpenApi spec.
1366///
1367/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
1368///
1369/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
1370///
1371/// * `xml(...)` Can be used to define [`Xml`][xml] object properties for the parameter type.
1372/// See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
1373///
1374/// * `nullable` Defines property is nullable (note this is different to non-required).
1375///
1376/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
1377/// division will result an `integer`. Value must be strictly above _`0`_.
1378///
1379/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
1380///
1381/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
1382///
1383/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
1384///
1385/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
1386///
1387/// * `max_length = ...` Can be used to define maximum length for `string` types.
1388///
1389/// * `min_length = ...` Can be used to define minimum length for `string` types.
1390///
1391/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
1392///
1393/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
1394/// be non-negative integer.
1395///
1396/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
1397/// be non-negative integer.
1398///
1399/// ##### Parameter Formats
1400/// ```test
1401/// ("name" = ParameterType, ParameterIn, ...)
1402/// ("name", ParameterIn, ...)
1403/// ```
1404///
1405/// **For example:**
1406///
1407/// ```text
1408/// params(
1409/// ("limit" = i32, Query),
1410/// ("x-custom-header" = String, Header, description = "Custom header"),
1411/// ("id" = String, Path, deprecated, description = "Pet database id"),
1412/// ("name", Path, deprecated, description = "Pet name"),
1413/// (
1414/// "value" = inline(Option<[String]>),
1415/// Query,
1416/// description = "Value description",
1417/// style = Form,
1418/// allow_reserved,
1419/// deprecated,
1420/// explode,
1421/// example = json!(["Value"])),
1422/// max_length = 10,
1423/// min_items = 1
1424/// )
1425/// )
1426/// ```
1427///
1428/// ## IntoParams Type
1429///
1430/// In the IntoParams parameters format, the parameters are specified using an identifier for a type
1431/// that implements [`IntoParams`][into_params]. See [`IntoParams`][into_params] for an
1432/// example.
1433///
1434/// ```text
1435/// params(MyParameters)
1436/// ```
1437///
1438/// **Note!** that `MyParameters` can also be used in combination with the [tuples
1439/// representation](#tuples) or other structs.
1440/// ```text
1441/// params(
1442/// MyParameters1,
1443/// MyParameters2,
1444/// ("id" = String, Path, deprecated, description = "Pet database id"),
1445/// )
1446/// ```
1447///
1448/// # Security Requirement Attributes
1449///
1450/// * `name` Define the name for security requirement. This must match to name of existing
1451/// [`SecurityScheme`][security_scheme].
1452/// * `scopes = [...]` Define the list of scopes needed. These must be scopes defined already in
1453/// existing [`SecurityScheme`][security_scheme].
1454///
1455/// **Security Requirement supported formats:**
1456///
1457/// ```text
1458/// (),
1459/// ("name" = []),
1460/// ("name" = ["scope1", "scope2"]),
1461/// ("name" = ["scope1", "scope2"], "name2" = []),
1462/// ```
1463///
1464/// Leaving empty _`()`_ creates an empty [`SecurityRequirement`][security] this is useful when
1465/// security requirement is optional for operation.
1466///
1467/// You can define multiple security requirements within same parenthesis separated by comma. This
1468/// allows you to define keys that must be simultaneously provided for the endpoint / API.
1469///
1470/// _**Following could be explained as: Security is optional and if provided it must either contain
1471/// `api_key` or `key AND key2`.**_
1472/// ```text
1473/// (),
1474/// ("api_key" = []),
1475/// ("key" = [], "key2" = []),
1476/// ```
1477///
1478/// # Extensions Requirements Attributes
1479///
1480/// * `x-property` defines the name of the extension.
1481/// * `json!(...)` defines the value associated with the named extension as a `serde_json::Value`.
1482///
1483/// **Extensions Requitement supported formats:**
1484///
1485/// ```text
1486/// ("x-property" = json!({ "type": "mock" }) ),
1487/// ("x-an-extension" = json!({ "type": "mock" }) ),
1488/// ("x-another-extension" = json!( "body" ) ),
1489/// ```
1490///
1491/// # actix_extras feature support for actix-web
1492///
1493/// **actix_extras** feature gives **utoipa** ability to parse path operation information from **actix-web** types and macros.
1494///
1495/// 1. Ability to parse `path` from **actix-web** path attribute macros e.g. _`#[get(...)]`_ or
1496/// `#[route(...)]`.
1497/// 2. Ability to parse [`std::primitive`] or [`String`] or [`tuple`] typed `path` parameters from **actix-web** _`web::Path<...>`_.
1498/// 3. Ability to parse `path` and `query` parameters form **actix-web** _`web::Path<...>`_, _`web::Query<...>`_ types
1499/// with [`IntoParams`][into_params] trait.
1500///
1501/// See the **actix_extras** in action in examples [todo-actix](https://github.com/juhaku/utoipa/tree/master/examples/todo-actix).
1502///
1503/// With **actix_extras** feature enabled the you can leave out definitions for **path**, **operation**
1504/// and **parameter types**.
1505/// ```rust
1506/// use actix_web::{get, web, HttpResponse, Responder};
1507/// use serde_json::json;
1508///
1509/// /// Get Pet by id
1510/// #[utoipa::path(
1511/// responses(
1512/// (status = 200, description = "Pet found from database")
1513/// ),
1514/// params(
1515/// ("id", description = "Pet id"),
1516/// )
1517/// )]
1518/// #[get("/pet/{id}")]
1519/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1520/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1521/// }
1522/// ```
1523///
1524/// With **actix_extras** you may also not to list any _**params**_ if you do not want to specify any description for them. Params are
1525/// resolved from path and the argument types of handler
1526/// ```rust
1527/// use actix_web::{get, web, HttpResponse, Responder};
1528/// use serde_json::json;
1529///
1530/// /// Get Pet by id
1531/// #[utoipa::path(
1532/// responses(
1533/// (status = 200, description = "Pet found from database")
1534/// )
1535/// )]
1536/// #[get("/pet/{id}")]
1537/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1538/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1539/// }
1540/// ```
1541///
1542/// # rocket_extras feature support for rocket
1543///
1544/// **rocket_extras** feature enhances path operation parameter support. It gives **utoipa** ability to parse `path`, `path parameters`
1545/// and `query parameters` based on arguments given to **rocket** proc macros such as _**`#[get(...)]`**_.
1546///
1547/// 1. It is able to parse parameter types for [primitive types][primitive], [`String`], [`Vec`], [`Option`] or [`std::path::PathBuf`]
1548/// type.
1549/// 2. It is able to determine `parameter_in` for [`IntoParams`][into_params] trait used for `FromForm` type of query parameters.
1550///
1551/// See the **rocket_extras** in action in examples [rocket-todo](https://github.com/juhaku/utoipa/tree/master/examples/rocket-todo).
1552///
1553///
1554/// # axum_extras feature support for axum
1555///
1556/// **axum_extras** feature enhances parameter support for path operation in following ways.
1557///
1558/// 1. It allows users to use tuple style path parameters e.g. _`Path((id, name)): Path<(i32, String)>`_ and resolves
1559/// parameter names and types from it.
1560/// 2. It enhances [`IntoParams` derive][into_params_derive] functionality by automatically resolving _`parameter_in`_ from
1561/// _`Path<...>`_ or _`Query<...>`_ handler function arguments.
1562///
1563/// _**Resole path argument types from tuple style handler arguments.**_
1564/// ```rust
1565/// # use axum::extract::Path;
1566/// /// Get todo by id and name.
1567/// #[utoipa::path(
1568/// get,
1569/// path = "/todo/{id}",
1570/// params(
1571/// ("id", description = "Todo id"),
1572/// ("name", description = "Todo name")
1573/// ),
1574/// responses(
1575/// (status = 200, description = "Get todo success", body = String)
1576/// )
1577/// )]
1578/// async fn get_todo(
1579/// Path((id, name)): Path<(i32, String)>
1580/// ) -> String {
1581/// String::new()
1582/// }
1583/// ```
1584///
1585/// _**Use `IntoParams` to resolve query parameters.**_
1586/// ```rust
1587/// # use serde::Deserialize;
1588/// # use utoipa::IntoParams;
1589/// # use axum::{extract::Query, Json};
1590/// #[derive(Deserialize, IntoParams)]
1591/// struct TodoSearchQuery {
1592/// /// Search by value. Search is incase sensitive.
1593/// value: String,
1594/// /// Search by `done` status.
1595/// done: bool,
1596/// }
1597///
1598/// /// Search Todos by query params.
1599/// #[utoipa::path(
1600/// get,
1601/// path = "/todo/search",
1602/// params(
1603/// TodoSearchQuery
1604/// ),
1605/// responses(
1606/// (status = 200, description = "List matching todos by query", body = [String])
1607/// )
1608/// )]
1609/// async fn search_todos(
1610/// query: Query<TodoSearchQuery>,
1611/// ) -> Json<Vec<String>> {
1612/// Json(vec![])
1613/// }
1614/// ```
1615///
1616/// # Defining file uploads
1617///
1618/// File uploads can be defined in accordance to Open API specification [file uploads][file_uploads].
1619///
1620///
1621/// _**Example sending `jpg` and `png` images as `application/octet-stream`.**_
1622/// ```rust
1623/// #[utoipa::path(
1624/// post,
1625/// request_body(
1626/// content(
1627/// ("image/png"),
1628/// ("image/jpg"),
1629/// ),
1630/// ),
1631/// path = "/test_images"
1632/// )]
1633/// async fn test_images(_body: Vec<u8>) {}
1634/// ```
1635///
1636/// _**Example of sending `multipart` form.**_
1637/// ```rust
1638/// #[derive(utoipa::ToSchema)]
1639/// struct MyForm {
1640/// order_id: i32,
1641/// #[schema(content_media_type = "application/octet-stream")]
1642/// file_bytes: Vec<u8>,
1643/// }
1644///
1645/// #[utoipa::path(
1646/// post,
1647/// request_body(content = inline(MyForm), content_type = "multipart/form-data"),
1648/// path = "/test_multipart"
1649/// )]
1650/// async fn test_multipart(_body: MyForm) {}
1651/// ```
1652///
1653/// _**Example of sending arbitrary binary content as `application/octet-stream`.**_
1654/// ```rust
1655/// #[utoipa::path(
1656/// post,
1657/// request_body = Vec<u8>,
1658/// path = "/test-octet-stream",
1659/// responses(
1660/// (status = 200, description = "success response")
1661/// ),
1662/// )]
1663/// async fn test_octet_stream(_body: Vec<u8>) {}
1664/// ```
1665///
1666/// _**Example of sending `png` image as `base64` encoded.**_
1667/// ```rust
1668/// #[derive(utoipa::ToSchema)]
1669/// #[schema(content_encoding = "base64")]
1670/// struct MyPng(String);
1671///
1672/// #[utoipa::path(
1673/// post,
1674/// request_body(content = inline(MyPng), content_type = "image/png"),
1675/// path = "/test_png",
1676/// responses(
1677/// (status = 200, description = "success response")
1678/// ),
1679/// )]
1680/// async fn test_png(_body: MyPng) {}
1681/// ```
1682///
1683/// # Examples
1684///
1685/// _**More complete example.**_
1686/// ```rust
1687/// # #[derive(utoipa::ToSchema)]
1688/// # struct Pet {
1689/// # id: u64,
1690/// # name: String,
1691/// # }
1692/// #
1693/// #[utoipa::path(
1694/// post,
1695/// operation_id = "custom_post_pet",
1696/// path = "/pet",
1697/// tag = "pet_handlers",
1698/// request_body(content = Pet, description = "Pet to store the database", content_type = "application/json"),
1699/// responses(
1700/// (status = 200, description = "Pet stored successfully", body = Pet, content_type = "application/json",
1701/// headers(
1702/// ("x-cache-len" = String, description = "Cache length")
1703/// ),
1704/// example = json!({"id": 1, "name": "bob the cat"})
1705/// ),
1706/// ),
1707/// params(
1708/// ("x-csrf-token" = String, Header, deprecated, description = "Current csrf token of user"),
1709/// ),
1710/// security(
1711/// (),
1712/// ("my_auth" = ["read:items", "edit:items"]),
1713/// ("token_jwt" = [])
1714/// )
1715/// )]
1716/// fn post_pet(pet: Pet) -> Pet {
1717/// Pet {
1718/// id: 4,
1719/// name: "bob the cat".to_string(),
1720/// }
1721/// }
1722/// ```
1723///
1724/// _**More minimal example with the defaults.**_
1725/// ```rust
1726/// # #[derive(utoipa::ToSchema)]
1727/// # struct Pet {
1728/// # id: u64,
1729/// # name: String,
1730/// # }
1731/// #
1732/// #[utoipa::path(
1733/// post,
1734/// path = "/pet",
1735/// request_body = Pet,
1736/// responses(
1737/// (status = 200, description = "Pet stored successfully", body = Pet,
1738/// headers(
1739/// ("x-cache-len", description = "Cache length")
1740/// )
1741/// ),
1742/// ),
1743/// params(
1744/// ("x-csrf-token", Header, description = "Current csrf token of user"),
1745/// )
1746/// )]
1747/// fn post_pet(pet: Pet) -> Pet {
1748/// Pet {
1749/// id: 4,
1750/// name: "bob the cat".to_string(),
1751/// }
1752/// }
1753/// ```
1754///
1755/// _**Use of Rust's own `#[deprecated]` attribute will reflect to the generated OpenAPI spec and mark this operation as deprecated.**_
1756/// ```rust
1757/// # use actix_web::{get, web, HttpResponse, Responder};
1758/// # use serde_json::json;
1759/// #[utoipa::path(
1760/// responses(
1761/// (status = 200, description = "Pet found from database")
1762/// ),
1763/// params(
1764/// ("id", description = "Pet id"),
1765/// )
1766/// )]
1767/// #[get("/pet/{id}")]
1768/// #[deprecated]
1769/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1770/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1771/// }
1772/// ```
1773///
1774/// _**Define context path for endpoint. The resolved **path** shown in OpenAPI doc will be `/api/pet/{id}`.**_
1775/// ```rust
1776/// # use actix_web::{get, web, HttpResponse, Responder};
1777/// # use serde_json::json;
1778/// #[utoipa::path(
1779/// context_path = "/api",
1780/// responses(
1781/// (status = 200, description = "Pet found from database")
1782/// )
1783/// )]
1784/// #[get("/pet/{id}")]
1785/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1786/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1787/// }
1788/// ```
1789///
1790/// _**Example with multiple return types**_
1791/// ```rust
1792/// # trait User {}
1793/// # #[derive(utoipa::ToSchema)]
1794/// # struct User1 {
1795/// # id: String
1796/// # }
1797/// # impl User for User1 {}
1798/// # #[derive(utoipa::ToSchema)]
1799/// # struct User2 {
1800/// # id: String
1801/// # }
1802/// # impl User for User2 {}
1803/// #[utoipa::path(
1804/// get,
1805/// path = "/user",
1806/// responses(
1807/// (status = 200, content(
1808/// (User1 = "application/vnd.user.v1+json", example = json!({"id": "id".to_string()})),
1809/// (User2 = "application/vnd.user.v2+json", example = json!({"id": 2}))
1810/// )
1811/// )
1812/// )
1813/// )]
1814/// fn get_user() -> Box<dyn User> {
1815/// Box::new(User1 {id: "id".to_string()})
1816/// }
1817/// ````
1818///
1819/// _**Example with multiple examples on single response.**_
1820/// ```rust
1821/// # #[derive(serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
1822/// # struct User {
1823/// # name: String
1824/// # }
1825/// #[utoipa::path(
1826/// get,
1827/// path = "/user",
1828/// responses(
1829/// (status = 200, body = User,
1830/// examples(
1831/// ("Demo" = (summary = "This is summary", description = "Long description",
1832/// value = json!(User{name: "Demo".to_string()}))),
1833/// ("John" = (summary = "Another user", value = json!({"name": "John"})))
1834/// )
1835/// )
1836/// )
1837/// )]
1838/// fn get_user() -> User {
1839/// User {name: "John".to_string()}
1840/// }
1841/// ```
1842///
1843/// _**Example of using links in response.**_
1844/// ```rust
1845/// # use serde_json::json;
1846/// #[utoipa::path(
1847/// get,
1848/// path = "/test-links",
1849/// responses(
1850/// (status = 200, description = "success response",
1851/// links(
1852/// ("getFoo" = (
1853/// operation_id = "test_links",
1854/// parameters(("key" = "value"), ("json_value" = json!(1))),
1855/// request_body = "this is body",
1856/// server(url = "http://localhost")
1857/// )),
1858/// ("getBar" = (
1859/// operation_ref = "this is ref"
1860/// ))
1861/// )
1862/// )
1863/// ),
1864/// )]
1865/// async fn test_links() -> &'static str {
1866/// ""
1867/// }
1868/// ```
1869///
1870/// [in_enum]: openapi/path/enum.ParameterIn.html
1871/// [path]: trait.Path.html
1872/// [to_schema]: trait.ToSchema.html
1873/// [openapi]: derive.OpenApi.html
1874/// [security]: openapi/security/struct.SecurityRequirement.html
1875/// [security_scheme]: openapi/security/enum.SecurityScheme.html
1876/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
1877/// [into_params]: trait.IntoParams.html
1878/// [style]: openapi/path/enum.ParameterStyle.html
1879/// [into_responses_trait]: trait.IntoResponses.html
1880/// [into_params_derive]: derive.IntoParams.html
1881/// [to_response_trait]: trait.ToResponse.html
1882/// [known_format]: openapi/schema/enum.KnownFormat.html
1883/// [xml]: openapi/xml/struct.Xml.html
1884/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
1885/// [relative_references]: https://spec.openapis.org/oas/latest.html#relative-references-in-uris
1886/// [operation]: openapi/path/struct.Operation.html
1887/// [expression]: https://spec.openapis.org/oas/latest.html#runtime-expressions
1888/// [const]: https://doc.rust-lang.org/std/keyword.const.html
1889/// [include_str]: https://doc.rust-lang.org/std/macro.include_str.html
1890/// [server_derive_syntax]: derive.OpenApi.html#servers-attribute-syntax
1891/// [server]: openapi/server/struct.Server.html
1892/// [file_uploads]: <https://spec.openapis.org/oas/v3.1.0.html#considerations-for-file-uploads>
1893pub fn path(attr: TokenStream, item: TokenStream) -> TokenStream {
1894 let path_attribute = syn::parse_macro_input!(attr as PathAttr);
1895
1896 #[cfg(any(
1897 feature = "actix_extras",
1898 feature = "rocket_extras",
1899 feature = "axum_extras",
1900 feature = "auto_into_responses"
1901 ))]
1902 let mut path_attribute = path_attribute;
1903
1904 let ast_fn = match syn::parse::<ItemFn>(item) {
1905 Ok(ast_fn) => ast_fn,
1906 Err(error) => return error.into_compile_error().into_token_stream().into(),
1907 };
1908
1909 #[cfg(feature = "auto_into_responses")]
1910 {
1911 if let Some(responses) = ext::auto_types::parse_fn_operation_responses(&ast_fn) {
1912 path_attribute.responses_from_into_responses(responses);
1913 };
1914 }
1915
1916 let mut resolved_methods = match PathOperations::resolve_operation(&ast_fn) {
1917 Ok(operation) => operation,
1918 Err(diagnostics) => return diagnostics.into_token_stream().into(),
1919 };
1920 let resolved_path = PathOperations::resolve_path(
1921 &resolved_methods
1922 .as_mut()
1923 .map(|operation| mem::take(&mut operation.path).to_string())
1924 .or_else(|| path_attribute.path.as_ref().map(|path| path.to_string())), // cannot use mem take because we need this later
1925 );
1926
1927 #[cfg(any(
1928 feature = "actix_extras",
1929 feature = "rocket_extras",
1930 feature = "axum_extras"
1931 ))]
1932 let mut resolved_path = resolved_path;
1933
1934 #[cfg(any(
1935 feature = "actix_extras",
1936 feature = "rocket_extras",
1937 feature = "axum_extras"
1938 ))]
1939 {
1940 use ext::ArgumentResolver;
1941 use path::parameter::Parameter;
1942 let path_args = resolved_path.as_mut().map(|path| mem::take(&mut path.args));
1943 let body = resolved_methods
1944 .as_mut()
1945 .map(|path| mem::take(&mut path.body))
1946 .unwrap_or_default();
1947
1948 let (arguments, into_params_types, body) =
1949 match PathOperations::resolve_arguments(&ast_fn.sig.inputs, path_args, body) {
1950 Ok(args) => args,
1951 Err(diagnostics) => return diagnostics.into_token_stream().into(),
1952 };
1953
1954 let parameters = arguments
1955 .into_iter()
1956 .flatten()
1957 .map(Parameter::from)
1958 .chain(into_params_types.into_iter().flatten().map(Parameter::from));
1959 path_attribute.update_parameters_ext(parameters);
1960
1961 path_attribute.update_request_body(body);
1962 }
1963
1964 let path = Path::new(path_attribute, &ast_fn.sig.ident)
1965 .ext_methods(resolved_methods.map(|operation| operation.methods))
1966 .path(resolved_path.map(|path| path.path))
1967 .doc_comments(CommentAttributes::from_attributes(&ast_fn.attrs).0)
1968 .deprecated(ast_fn.attrs.has_deprecated());
1969
1970 let handler = path::handler::Handler {
1971 path,
1972 handler_fn: &ast_fn,
1973 };
1974 handler.to_token_stream().into()
1975}
1976
1977#[proc_macro_derive(OpenApi, attributes(openapi))]
1978/// Generate OpenApi base object with defaults from
1979/// project settings.
1980///
1981/// This is `#[derive]` implementation for [`OpenApi`][openapi] trait. The macro accepts one `openapi` argument.
1982///
1983/// # OpenApi `#[openapi(...)]` attributes
1984///
1985/// * `paths(...)` List of method references having attribute [`#[utoipa::path]`][path] macro.
1986/// * `components(schemas(...), responses(...))` Takes available _`component`_ configurations. Currently only
1987/// _`schema`_ and _`response`_ components are supported.
1988/// * `schemas(...)` List of [`ToSchema`][to_schema]s in OpenAPI schema.
1989/// * `responses(...)` List of types that implement [`ToResponse`][to_response_trait].
1990/// * `modifiers(...)` List of items implementing [`Modify`][modify] trait for runtime OpenApi modification.
1991/// See the [trait documentation][modify] for more details.
1992/// * `security(...)` List of [`SecurityRequirement`][security]s global to all operations.
1993/// See more details in [`#[utoipa::path(...)]`][path] [attribute macro security options][path_security].
1994/// * `tags(...)` List of [`Tag`][tags]s which must match the tag _**path operation**_. Tags can be used to
1995/// define extra information for the API to produce richer documentation. See [tags attribute syntax][tags_syntax].
1996/// * `external_docs(...)` Can be used to reference external resource to the OpenAPI doc for extended documentation.
1997/// External docs can be in [`OpenApi`][openapi_struct] or in [`Tag`][tags] level.
1998/// * `servers(...)` Define [`servers`][servers] as derive argument to the _`OpenApi`_. Servers
1999/// are completely optional and thus can be omitted from the declaration. See [servers attribute
2000/// syntax][servers_syntax]
2001/// * `info(...)` Declare [`Info`][info] attribute values used to override the default values
2002/// generated from Cargo environment variables. **Note!** Defined attributes will override the
2003/// whole attribute from generated values of Cargo environment variables. E.g. defining
2004/// `contact(name = ...)` will ultimately override whole contact of info and not just partially
2005/// the name. See [info attribute syntax][info_syntax]
2006/// * `nest(...)` Allows nesting [`OpenApi`][openapi_struct]s to this _`OpenApi`_ instance. Nest
2007/// takes comma separated list of tuples of nested `OpenApi`s. _`OpenApi`_ instance must
2008/// implement [`OpenApi`][openapi] trait. Nesting allows defining one `OpenApi` per defined path.
2009/// If more instances is defined only latest one will be rentained.
2010/// See the _[nest(...) attribute syntax below]( #nest-attribute-syntax )_
2011///
2012///
2013/// OpenApi derive macro will also derive [`Info`][info] for OpenApi specification using Cargo
2014/// environment variables.
2015///
2016/// * env `CARGO_PKG_NAME` map to info `title`
2017/// * env `CARGO_PKG_VERSION` map to info `version`
2018/// * env `CARGO_PKG_DESCRIPTION` map info `description`
2019/// * env `CARGO_PKG_AUTHORS` map to contact `name` and `email` **only first author will be used**
2020/// * env `CARGO_PKG_LICENSE` map to info `license`
2021///
2022/// # `info(...)` attribute syntax
2023///
2024/// * `title = ...` Define title of the API. It can be [`str`] or an
2025/// expression such as [`include_str!`][include_str] or static [`const`][const] reference.
2026/// * `terms_of_service = ...` Define URL to the Terms of Service for the API. It can be [`str`] or an
2027/// expression such as [`include_str!`][include_str] or static [`const`][const] reference. Value
2028/// must be valid URL.
2029/// * `description = ...` Define description of the API. Markdown can be used for rich text
2030/// representation. It can be [`str`] or an expression such as [`include_str!`][include_str] or static
2031/// [`const`][const] reference.
2032/// * `version = ...` Override default version from _`Cargo.toml`_. Value can be [`str`] or an
2033/// expression such as [`include_str!`][include_str] or static [`const`][const] reference.
2034/// * `contact(...)` Used to override the whole contact generated from environment variables.
2035/// * `name = ...` Define identifying name of contact person / organization. It Can be a literal string.
2036/// * `email = ...` Define email address of the contact person / organization. It can be a literal string.
2037/// * `url = ...` Define URL pointing to the contact information. It must be in URL formatted string.
2038/// * `license(...)` Used to override the whole license generated from environment variables.
2039/// * `name = ...` License name of the API. It can be a literal string.
2040/// * `url = ...` Define optional URL of the license. It must be URL formatted string.
2041///
2042/// # `tags(...)` attribute syntax
2043///
2044/// * `name = ...` Must be provided, can be [`str`] or an expression such as [`include_str!`][include_str]
2045/// or static [`const`][const] reference.
2046/// * `description = ...` Optional description for the tag. Can be either or static [`str`]
2047/// or an expression e.g. _`include_str!(...)`_ macro call or reference to static [`const`][const].
2048/// * `external_docs(...)` Optional links to external documents.
2049/// * `url = ...` Mandatory URL for external documentation.
2050/// * `description = ...` Optional description for the _`url`_ link.
2051///
2052/// # `servers(...)` attribute syntax
2053///
2054/// * `url = ...` Define the url for server. It can be literal string.
2055/// * `description = ...` Define description for the server. It can be literal string.
2056/// * `variables(...)` Can be used to define variables for the url.
2057/// * `name = ...` Is the first argument within parentheses. It must be literal string.
2058/// * `default = ...` Defines a default value for the variable if nothing else will be
2059/// provided. If _`enum_values`_ is defined the _`default`_ must be found within the enum
2060/// options. It can be a literal string.
2061/// * `description = ...` Define the description for the variable. It can be a literal string.
2062/// * `enum_values(...)` Define list of possible values for the variable. Values must be
2063/// literal strings.
2064///
2065/// _**Example server variable definition.**_
2066/// ```text
2067/// ("username" = (default = "demo", description = "Default username for API")),
2068/// ("port" = (enum_values("8080", "5000", "4545")))
2069/// ```
2070///
2071/// # `nest(...)` attribute syntax
2072///
2073/// * `path = ...` Define mandatory path for nesting the [`OpenApi`][openapi_struct].
2074/// * `api = ...` Define mandatory path to struct that implements [`OpenApi`][openapi] trait.
2075/// The fully qualified path (_`path::to`_) will become the default _`tag`_ for the nested
2076/// `OpenApi` endpoints if provided.
2077/// * `tags = [...]` Define optional tags what are appended to the existing list of tags.
2078///
2079/// _**Example of nest definition**_
2080/// ```text
2081/// (path = "path/to/nest", api = path::to::NestableApi),
2082/// (path = "path/to/nest", api = path::to::NestableApi, tags = ["nestableapi", ...])
2083/// ```
2084///
2085/// # Examples
2086///
2087/// _**Define OpenApi schema with some paths and components.**_
2088/// ```rust
2089/// # use utoipa::{OpenApi, ToSchema};
2090/// #
2091/// #[derive(ToSchema)]
2092/// struct Pet {
2093/// name: String,
2094/// age: i32,
2095/// }
2096///
2097/// #[derive(ToSchema)]
2098/// enum Status {
2099/// Active, InActive, Locked,
2100/// }
2101///
2102/// #[utoipa::path(get, path = "/pet")]
2103/// fn get_pet() -> Pet {
2104/// Pet {
2105/// name: "bob".to_string(),
2106/// age: 8,
2107/// }
2108/// }
2109///
2110/// #[utoipa::path(get, path = "/status")]
2111/// fn get_status() -> Status {
2112/// Status::Active
2113/// }
2114///
2115/// #[derive(OpenApi)]
2116/// #[openapi(
2117/// paths(get_pet, get_status),
2118/// components(schemas(Pet, Status)),
2119/// security(
2120/// (),
2121/// ("my_auth" = ["read:items", "edit:items"]),
2122/// ("token_jwt" = [])
2123/// ),
2124/// tags(
2125/// (name = "pets::api", description = "All about pets",
2126/// external_docs(url = "http://more.about.pets.api", description = "Find out more"))
2127/// ),
2128/// external_docs(url = "http://more.about.our.apis", description = "More about our APIs")
2129/// )]
2130/// struct ApiDoc;
2131/// ```
2132///
2133/// _**Define servers to OpenApi.**_
2134/// ```rust
2135/// # use utoipa::OpenApi;
2136/// #[derive(OpenApi)]
2137/// #[openapi(
2138/// servers(
2139/// (url = "http://localhost:8989", description = "Local server"),
2140/// (url = "http://api.{username}:{port}", description = "Remote API",
2141/// variables(
2142/// ("username" = (default = "demo", description = "Default username for API")),
2143/// ("port" = (default = "8080", enum_values("8080", "5000", "3030"), description = "Supported ports for API"))
2144/// )
2145/// )
2146/// )
2147/// )]
2148/// struct ApiDoc;
2149/// ```
2150///
2151/// _**Define info attribute values used to override auto generated ones from Cargo environment
2152/// variables.**_
2153/// ```compile_fail
2154/// # use utoipa::OpenApi;
2155/// #[derive(OpenApi)]
2156/// #[openapi(info(
2157/// title = "title override",
2158/// description = include_str!("./path/to/content"), // fail compile cause no such file
2159/// contact(name = "Test")
2160/// ))]
2161/// struct ApiDoc;
2162/// ```
2163///
2164/// _**Create OpenAPI with reusable response.**_
2165/// ```rust
2166/// #[derive(utoipa::ToSchema)]
2167/// struct Person {
2168/// name: String,
2169/// }
2170///
2171/// /// Person list response
2172/// #[derive(utoipa::ToResponse)]
2173/// struct PersonList(Vec<Person>);
2174///
2175/// #[utoipa::path(
2176/// get,
2177/// path = "/person-list",
2178/// responses(
2179/// (status = 200, response = PersonList)
2180/// )
2181/// )]
2182/// fn get_persons() -> Vec<Person> {
2183/// vec![]
2184/// }
2185///
2186/// #[derive(utoipa::OpenApi)]
2187/// #[openapi(
2188/// components(
2189/// schemas(Person),
2190/// responses(PersonList)
2191/// )
2192/// )]
2193/// struct ApiDoc;
2194/// ```
2195///
2196/// _**Nest _`UserApi`_ to the current api doc instance.**_
2197/// ```rust
2198/// # use utoipa::OpenApi;
2199/// #
2200/// #[utoipa::path(get, path = "/api/v1/status")]
2201/// fn test_path_status() {}
2202///
2203/// #[utoipa::path(get, path = "/test")]
2204/// fn user_test_path() {}
2205///
2206/// #[derive(OpenApi)]
2207/// #[openapi(paths(user_test_path))]
2208/// struct UserApi;
2209///
2210/// #[derive(OpenApi)]
2211/// #[openapi(
2212/// paths(
2213/// test_path_status
2214/// ),
2215/// nest(
2216/// (path = "/api/v1/user", api = UserApi),
2217/// )
2218/// )]
2219/// struct ApiDoc;
2220/// ```
2221///
2222/// [openapi]: trait.OpenApi.html
2223/// [openapi_struct]: openapi/struct.OpenApi.html
2224/// [to_schema]: derive.ToSchema.html
2225/// [path]: attr.path.html
2226/// [modify]: trait.Modify.html
2227/// [info]: openapi/info/struct.Info.html
2228/// [security]: openapi/security/struct.SecurityRequirement.html
2229/// [path_security]: attr.path.html#security-requirement-attributes
2230/// [tags]: openapi/tag/struct.Tag.html
2231/// [to_response_trait]: trait.ToResponse.html
2232/// [servers]: openapi/server/index.html
2233/// [const]: https://doc.rust-lang.org/std/keyword.const.html
2234/// [tags_syntax]: #tags-attribute-syntax
2235/// [info_syntax]: #info-attribute-syntax
2236/// [servers_syntax]: #servers-attribute-syntax
2237/// [include_str]: https://doc.rust-lang.org/std/macro.include_str.html
2238pub fn openapi(input: TokenStream) -> TokenStream {
2239 let DeriveInput { attrs, ident, .. } = syn::parse_macro_input!(input);
2240
2241 parse_openapi_attrs(&attrs)
2242 .map(|openapi_attr| OpenApi(openapi_attr, ident).to_token_stream())
2243 .map_or_else(syn::Error::into_compile_error, ToTokens::into_token_stream)
2244 .into()
2245}
2246
2247#[proc_macro_derive(IntoParams, attributes(param, into_params))]
2248/// Generate [path parameters][path_params] from struct's
2249/// fields.
2250///
2251/// This is `#[derive]` implementation for [`IntoParams`][into_params] trait.
2252///
2253/// Typically path parameters need to be defined within [`#[utoipa::path(...params(...))]`][path_params] section
2254/// for the endpoint. But this trait eliminates the need for that when [`struct`][struct]s are used to define parameters.
2255/// Still [`std::primitive`] and [`String`] path parameters or [`tuple`] style path parameters need to be defined
2256/// within `params(...)` section if description or other than default configuration need to be given.
2257///
2258/// You can use the Rust's own `#[deprecated]` attribute on field to mark it as
2259/// deprecated and it will reflect to the generated OpenAPI spec.
2260///
2261/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version
2262/// but this is is not supported in OpenAPI. OpenAPI has only a boolean flag to determine deprecation.
2263/// While it is totally okay to declare deprecated with reason
2264/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
2265///
2266/// Doc comment on struct fields will be used as description for the generated parameters.
2267/// ```rust
2268/// #[derive(utoipa::IntoParams)]
2269/// struct Query {
2270/// /// Query todo items by name.
2271/// name: String
2272/// }
2273/// ```
2274///
2275/// # IntoParams Container Attributes for `#[into_params(...)]`
2276///
2277/// The following attributes are available for use in on the container attribute `#[into_params(...)]` for the struct
2278/// deriving `IntoParams`:
2279///
2280/// * `names(...)` Define comma separated list of names for unnamed fields of struct used as a path parameter.
2281/// __Only__ supported on __unnamed structs__.
2282/// * `style = ...` Defines how all parameters are serialized by [`ParameterStyle`][style]. Default
2283/// values are based on _`parameter_in`_ attribute.
2284/// * `parameter_in = ...` = Defines where the parameters of this field are used with a value from
2285/// [`openapi::path::ParameterIn`][in_enum]. There is no default value, if this attribute is not
2286/// supplied, then the value is determined by the `parameter_in_provider` in
2287/// [`IntoParams::into_params()`](trait.IntoParams.html#tymethod.into_params).
2288/// * `rename_all = ...` Can be provided to alternatively to the serde's `rename_all` attribute. Effectively provides same functionality.
2289///
2290/// Use `names` to define name for single unnamed argument.
2291/// ```rust
2292/// # use utoipa::IntoParams;
2293/// #
2294/// #[derive(IntoParams)]
2295/// #[into_params(names("id"))]
2296/// struct Id(u64);
2297/// ```
2298///
2299/// Use `names` to define names for multiple unnamed arguments.
2300/// ```rust
2301/// # use utoipa::IntoParams;
2302/// #
2303/// #[derive(IntoParams)]
2304/// #[into_params(names("id", "name"))]
2305/// struct IdAndName(u64, String);
2306/// ```
2307///
2308/// # IntoParams Field Attributes for `#[param(...)]`
2309///
2310/// The following attributes are available for use in the `#[param(...)]` on struct fields:
2311///
2312/// * `style = ...` Defines how the parameter is serialized by [`ParameterStyle`][style]. Default values are based on _`parameter_in`_ attribute.
2313///
2314/// * `explode` Defines whether new _`parameter=value`_ pair is created for each parameter within _`object`_ or _`array`_.
2315///
2316/// * `allow_reserved` Defines whether reserved characters _`:/?#[]@!$&'()*+,;=`_ is allowed within value.
2317///
2318/// * `example = ...` Can be method reference or _`json!(...)`_. Given example
2319/// will override any example in underlying parameter type.
2320///
2321/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
2322/// This is useful in cases where the default type does not correspond to the actual type e.g. when
2323/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
2324/// The value can be any Rust type what normally could be used to serialize to JSON, or either virtual type _`Object`_
2325/// or _`Value`_.
2326/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
2327/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
2328///
2329/// * `inline` If set, the schema for this field's type needs to be a [`ToSchema`][to_schema], and
2330/// the schema definition will be inlined.
2331///
2332/// * `default = ...` Can be method reference or _`json!(...)`_.
2333///
2334/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
2335/// an open value as a string. By default the format is derived from the type of the property
2336/// according OpenApi spec.
2337///
2338/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*.
2339///
2340/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*.
2341///
2342/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to named fields.
2343/// See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
2344///
2345/// * `nullable` Defines property is nullable (note this is different to non-required).
2346///
2347/// * `required = ...` Can be used to enforce required status for the parameter. [See
2348/// rules][derive@IntoParams#field-nullability-and-required-rules]
2349///
2350/// * `rename = ...` Can be provided to alternatively to the serde's `rename` attribute. Effectively provides same functionality.
2351///
2352/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
2353/// division will result an `integer`. Value must be strictly above _`0`_.
2354///
2355/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
2356///
2357/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
2358///
2359/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
2360///
2361/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
2362///
2363/// * `max_length = ...` Can be used to define maximum length for `string` types.
2364///
2365/// * `min_length = ...` Can be used to define minimum length for `string` types.
2366///
2367/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
2368///
2369/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
2370/// be non-negative integer.
2371///
2372/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
2373/// be non-negative integer.
2374///
2375/// * `schema_with = ...` Use _`schema`_ created by provided function reference instead of the
2376/// default derived _`schema`_. The function must match to `fn() -> Into<RefOr<Schema>>`. It does
2377/// not accept arguments and must return anything that can be converted into `RefOr<Schema>`.
2378///
2379/// * `additional_properties = ...` Can be used to define free form types for maps such as
2380/// [`HashMap`](std::collections::HashMap) and [`BTreeMap`](std::collections::BTreeMap).
2381/// Free form type enables use of arbitrary types within map values.
2382/// Supports formats _`additional_properties`_ and _`additional_properties = true`_.
2383///
2384/// * `ignore` or `ignore = ...` Can be used to skip the field from being serialized to OpenAPI schema. It accepts either a literal `bool` value
2385/// or a path to a function that returns `bool` (`Fn() -> bool`).
2386///
2387/// #### Field nullability and required rules
2388///
2389/// Same rules for nullability and required status apply for _`IntoParams`_ field attributes as for
2390/// _`ToSchema`_ field attributes. [See the rules][`derive@ToSchema#field-nullability-and-required-rules`].
2391///
2392/// # Partial `#[serde(...)]` attributes support
2393///
2394/// IntoParams derive has partial support for [serde attributes]. These supported attributes will reflect to the
2395/// generated OpenAPI doc. The following attributes are currently supported:
2396///
2397/// * `rename_all = "..."` Supported at the container level.
2398/// * `rename = "..."` Supported **only** at the field level.
2399/// * `default` Supported at the container level and field level according to [serde attributes].
2400/// * `skip_serializing_if = "..."` Supported **only** at the field level.
2401/// * `with = ...` Supported **only** at field level.
2402/// * `skip_serializing = "..."` Supported **only** at the field or variant level.
2403/// * `skip_deserializing = "..."` Supported **only** at the field or variant level.
2404/// * `skip = "..."` Supported **only** at the field level.
2405///
2406/// Other _`serde`_ attributes will impact the serialization but will not be reflected on the generated OpenAPI doc.
2407///
2408/// # Examples
2409///
2410/// _**Demonstrate [`IntoParams`][into_params] usage with resolving `Path` and `Query` parameters
2411/// with _`actix-web`_**_.
2412/// ```rust
2413/// use actix_web::{get, HttpResponse, Responder};
2414/// use actix_web::web::{Path, Query};
2415/// use serde::Deserialize;
2416/// use serde_json::json;
2417/// use utoipa::IntoParams;
2418///
2419/// #[derive(Deserialize, IntoParams)]
2420/// struct PetPathArgs {
2421/// /// Id of pet
2422/// id: i64,
2423/// /// Name of pet
2424/// name: String,
2425/// }
2426///
2427/// #[derive(Deserialize, IntoParams)]
2428/// struct Filter {
2429/// /// Age filter for pets
2430/// #[deprecated]
2431/// #[param(style = Form, explode, allow_reserved, example = json!([10]))]
2432/// age: Option<Vec<i32>>,
2433/// }
2434///
2435/// #[utoipa::path(
2436/// params(PetPathArgs, Filter),
2437/// responses(
2438/// (status = 200, description = "success response")
2439/// )
2440/// )]
2441/// #[get("/pet/{id}/{name}")]
2442/// async fn get_pet(pet: Path<PetPathArgs>, query: Query<Filter>) -> impl Responder {
2443/// HttpResponse::Ok().json(json!({ "id": pet.id }))
2444/// }
2445/// ```
2446///
2447/// _**Demonstrate [`IntoParams`][into_params] usage with the `#[into_params(...)]` container attribute to
2448/// be used as a path query, and inlining a schema query field:**_
2449/// ```rust
2450/// use serde::Deserialize;
2451/// use utoipa::{IntoParams, ToSchema};
2452///
2453/// #[derive(Deserialize, ToSchema)]
2454/// #[serde(rename_all = "snake_case")]
2455/// enum PetKind {
2456/// Dog,
2457/// Cat,
2458/// }
2459///
2460/// #[derive(Deserialize, IntoParams)]
2461/// #[into_params(style = Form, parameter_in = Query)]
2462/// struct PetQuery {
2463/// /// Name of pet
2464/// name: Option<String>,
2465/// /// Age of pet
2466/// age: Option<i32>,
2467/// /// Kind of pet
2468/// #[param(inline)]
2469/// kind: PetKind
2470/// }
2471///
2472/// #[utoipa::path(
2473/// get,
2474/// path = "/get_pet",
2475/// params(PetQuery),
2476/// responses(
2477/// (status = 200, description = "success response")
2478/// )
2479/// )]
2480/// async fn get_pet(query: PetQuery) {
2481/// // ...
2482/// }
2483/// ```
2484///
2485/// _**Override `String` with `i64` using `value_type` attribute.**_
2486/// ```rust
2487/// # use utoipa::IntoParams;
2488/// #
2489/// #[derive(IntoParams)]
2490/// #[into_params(parameter_in = Query)]
2491/// struct Filter {
2492/// #[param(value_type = i64)]
2493/// id: String,
2494/// }
2495/// ```
2496///
2497/// _**Override `String` with `Object` using `value_type` attribute. _`Object`_ will render as `type: object` in OpenAPI spec.**_
2498/// ```rust
2499/// # use utoipa::IntoParams;
2500/// #
2501/// #[derive(IntoParams)]
2502/// #[into_params(parameter_in = Query)]
2503/// struct Filter {
2504/// #[param(value_type = Object)]
2505/// id: String,
2506/// }
2507/// ```
2508///
2509/// _**You can use a generic type to override the default type of the field.**_
2510/// ```rust
2511/// # use utoipa::IntoParams;
2512/// #
2513/// #[derive(IntoParams)]
2514/// #[into_params(parameter_in = Query)]
2515/// struct Filter {
2516/// #[param(value_type = Option<String>)]
2517/// id: String
2518/// }
2519/// ```
2520///
2521/// _**You can even override a [`Vec`] with another one.**_
2522/// ```rust
2523/// # use utoipa::IntoParams;
2524/// #
2525/// #[derive(IntoParams)]
2526/// #[into_params(parameter_in = Query)]
2527/// struct Filter {
2528/// #[param(value_type = Vec<i32>)]
2529/// id: Vec<String>
2530/// }
2531/// ```
2532///
2533/// _**We can override value with another [`ToSchema`][to_schema].**_
2534/// ```rust
2535/// # use utoipa::{IntoParams, ToSchema};
2536/// #
2537/// #[derive(ToSchema)]
2538/// struct Id {
2539/// value: i64,
2540/// }
2541///
2542/// #[derive(IntoParams)]
2543/// #[into_params(parameter_in = Query)]
2544/// struct Filter {
2545/// #[param(value_type = Id)]
2546/// id: String
2547/// }
2548/// ```
2549///
2550/// _**Example with validation attributes.**_
2551/// ```rust
2552/// #[derive(utoipa::IntoParams)]
2553/// struct Item {
2554/// #[param(maximum = 10, minimum = 5, multiple_of = 2.5)]
2555/// id: i32,
2556/// #[param(max_length = 10, min_length = 5, pattern = "[a-z]*")]
2557/// value: String,
2558/// #[param(max_items = 5, min_items = 1)]
2559/// items: Vec<String>,
2560/// }
2561/// ````
2562///
2563/// _**Use `schema_with` to manually implement schema for a field.**_
2564/// ```rust
2565/// # use utoipa::openapi::schema::{Object, ObjectBuilder};
2566/// fn custom_type() -> Object {
2567/// ObjectBuilder::new()
2568/// .schema_type(utoipa::openapi::schema::Type::String)
2569/// .format(Some(utoipa::openapi::SchemaFormat::Custom(
2570/// "email".to_string(),
2571/// )))
2572/// .description(Some("this is the description"))
2573/// .build()
2574/// }
2575///
2576/// #[derive(utoipa::IntoParams)]
2577/// #[into_params(parameter_in = Query)]
2578/// struct Query {
2579/// #[param(schema_with = custom_type)]
2580/// email: String,
2581/// }
2582/// ```
2583///
2584/// [to_schema]: trait.ToSchema.html
2585/// [known_format]: openapi/schema/enum.KnownFormat.html
2586/// [xml]: openapi/xml/struct.Xml.html
2587/// [into_params]: trait.IntoParams.html
2588/// [path_params]: attr.path.html#params-attributes
2589/// [struct]: https://doc.rust-lang.org/std/keyword.struct.html
2590/// [style]: openapi/path/enum.ParameterStyle.html
2591/// [in_enum]: openapi/path/enum.ParameterIn.html
2592/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2593/// [serde attributes]: https://serde.rs/attributes.html
2594/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
2595pub fn into_params(input: TokenStream) -> TokenStream {
2596 let DeriveInput {
2597 attrs,
2598 ident,
2599 generics,
2600 data,
2601 ..
2602 } = syn::parse_macro_input!(input);
2603
2604 let into_params = IntoParams {
2605 attrs,
2606 generics,
2607 data,
2608 ident,
2609 };
2610
2611 into_params.to_token_stream().into()
2612}
2613
2614#[proc_macro_derive(ToResponse, attributes(response, content, to_schema))]
2615/// Generate reusable OpenAPI response that can be used
2616/// in [`utoipa::path`][path] or in [`OpenApi`][openapi].
2617///
2618/// This is `#[derive]` implementation for [`ToResponse`][to_response] trait.
2619///
2620///
2621/// _`#[response]`_ attribute can be used to alter and add [response attributes](#toresponse-response-attributes).
2622///
2623/// _`#[content]`_ attributes is used to make enum variant a content of a specific type for the
2624/// response.
2625///
2626/// _`#[to_schema]`_ attribute is used to inline a schema for a response in unnamed structs or
2627/// enum variants with `#[content]` attribute. **Note!** [`ToSchema`] need to be implemented for
2628/// the field or variant type.
2629///
2630/// Type derived with _`ToResponse`_ uses provided doc comment as a description for the response. It
2631/// can alternatively be overridden with _`description = ...`_ attribute.
2632///
2633/// _`ToResponse`_ can be used in four different ways to generate OpenAPI response component.
2634///
2635/// 1. By decorating `struct` or `enum` with [`derive@ToResponse`] derive macro. This will create a
2636/// response with inlined schema resolved from the fields of the `struct` or `variants` of the
2637/// enum.
2638///
2639/// ```rust
2640/// # use utoipa::ToResponse;
2641/// #[derive(ToResponse)]
2642/// #[response(description = "Person response returns single Person entity")]
2643/// struct Person {
2644/// name: String,
2645/// }
2646/// ```
2647///
2648/// 2. By decorating unnamed field `struct` with [`derive@ToResponse`] derive macro. Unnamed field struct
2649/// allows users to use new type pattern to define one inner field which is used as a schema for
2650/// the generated response. This allows users to define `Vec` and `Option` response types.
2651/// Additionally these types can also be used with `#[to_schema]` attribute to inline the
2652/// field's type schema if it implements [`ToSchema`] derive macro.
2653///
2654/// ```rust
2655/// # #[derive(utoipa::ToSchema)]
2656/// # struct Person {
2657/// # name: String,
2658/// # }
2659/// /// Person list response
2660/// #[derive(utoipa::ToResponse)]
2661/// struct PersonList(Vec<Person>);
2662/// ```
2663///
2664/// 3. By decorating unit struct with [`derive@ToResponse`] derive macro. Unit structs will produce a
2665/// response without body.
2666///
2667/// ```rust
2668/// /// Success response which does not have body.
2669/// #[derive(utoipa::ToResponse)]
2670/// struct SuccessResponse;
2671/// ```
2672///
2673/// 4. By decorating `enum` with variants having `#[content(...)]` attribute. This allows users to
2674/// define multiple response content schemas to single response according to OpenAPI spec.
2675/// **Note!** Enum with _`content`_ attribute in variants cannot have enum level _`example`_ or
2676/// _`examples`_ defined. Instead examples need to be defined per variant basis. Additionally
2677/// these variants can also be used with `#[to_schema]` attribute to inline the variant's type schema
2678/// if it implements [`ToSchema`] derive macro.
2679///
2680/// ```rust
2681/// #[derive(utoipa::ToSchema)]
2682/// struct Admin {
2683/// name: String,
2684/// }
2685/// #[derive(utoipa::ToSchema)]
2686/// struct Admin2 {
2687/// name: String,
2688/// id: i32,
2689/// }
2690///
2691/// #[derive(utoipa::ToResponse)]
2692/// enum Person {
2693/// #[response(examples(
2694/// ("Person1" = (value = json!({"name": "name1"}))),
2695/// ("Person2" = (value = json!({"name": "name2"})))
2696/// ))]
2697/// Admin(#[content("application/vnd-custom-v1+json")] Admin),
2698///
2699/// #[response(example = json!({"name": "name3", "id": 1}))]
2700/// Admin2(#[content("application/vnd-custom-v2+json")] #[to_schema] Admin2),
2701/// }
2702/// ```
2703///
2704/// # ToResponse `#[response(...)]` attributes
2705///
2706/// * `description = "..."` Define description for the response as str. This can be used to
2707/// override the default description resolved from doc comments if present.
2708///
2709/// * `content_type = "..."` Can be used to override the default behavior
2710/// of auto resolving the content type from the `body` attribute. If defined the value should be valid
2711/// content type such as _`application/json`_ . By default the content type is _`text/plain`_
2712/// for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
2713/// for struct and mixed enum types.
2714///
2715/// * `headers(...)` Slice of response headers that are returned back to a caller.
2716///
2717/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
2718/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2719///
2720/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
2721/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
2722/// * `name = ...` This is first attribute and value must be literal string.
2723/// * `summary = ...` Short description of example. Value must be literal string.
2724/// * `description = ...` Long description of example. Attribute supports markdown for rich text
2725/// representation. Value must be literal string.
2726/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
2727/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2728/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
2729/// the _`value`_ attribute. Value must be literal string.
2730///
2731/// _**Example of example definition.**_
2732/// ```text
2733/// ("John" = (summary = "This is John", value = json!({"name": "John"})))
2734/// ```
2735///
2736/// # Examples
2737///
2738/// _**Use reusable response in operation handler.**_
2739/// ```rust
2740/// #[derive(utoipa::ToResponse)]
2741/// struct PersonResponse {
2742/// value: String
2743/// }
2744///
2745/// #[derive(utoipa::OpenApi)]
2746/// #[openapi(components(responses(PersonResponse)))]
2747/// struct Doc;
2748///
2749/// #[utoipa::path(
2750/// get,
2751/// path = "/api/person",
2752/// responses(
2753/// (status = 200, response = PersonResponse)
2754/// )
2755/// )]
2756/// fn get_person() -> PersonResponse {
2757/// PersonResponse { value: "person".to_string() }
2758/// }
2759/// ```
2760///
2761/// _**Create a response from named struct.**_
2762/// ```rust
2763/// /// This is description
2764/// ///
2765/// /// It will also be used in `ToSchema` if present
2766/// #[derive(utoipa::ToSchema, utoipa::ToResponse)]
2767/// #[response(
2768/// description = "Override description for response",
2769/// content_type = "text/xml"
2770/// )]
2771/// #[response(
2772/// example = json!({"name": "the name"}),
2773/// headers(
2774/// ("csrf-token", description = "response csrf token"),
2775/// ("random-id" = i32)
2776/// )
2777/// )]
2778/// struct Person {
2779/// name: String,
2780/// }
2781/// ```
2782///
2783/// _**Create inlined person list response.**_
2784/// ```rust
2785/// # #[derive(utoipa::ToSchema)]
2786/// # struct Person {
2787/// # name: String,
2788/// # }
2789/// /// Person list response
2790/// #[derive(utoipa::ToResponse)]
2791/// struct PersonList(#[to_schema] Vec<Person>);
2792/// ```
2793///
2794/// _**Create enum response from variants.**_
2795/// ```rust
2796/// #[derive(utoipa::ToResponse)]
2797/// enum PersonType {
2798/// Value(String),
2799/// Foobar,
2800/// }
2801/// ```
2802///
2803/// [to_response]: trait.ToResponse.html
2804/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2805/// [path]: attr.path.html
2806/// [openapi]: derive.OpenApi.html
2807pub fn to_response(input: TokenStream) -> TokenStream {
2808 let DeriveInput {
2809 attrs,
2810 ident,
2811 generics,
2812 data,
2813 ..
2814 } = syn::parse_macro_input!(input);
2815
2816 ToResponse::new(attrs, &data, generics, ident)
2817 .as_ref()
2818 .map_or_else(Diagnostics::to_token_stream, ToResponse::to_token_stream)
2819 .into()
2820}
2821
2822#[proc_macro_derive(
2823 IntoResponses,
2824 attributes(response, to_schema, ref_response, to_response)
2825)]
2826/// Generate responses with status codes what
2827/// can be attached to the [`utoipa::path`][path_into_responses].
2828///
2829/// This is `#[derive]` implementation of [`IntoResponses`][into_responses] trait. [`derive@IntoResponses`]
2830/// can be used to decorate _`structs`_ and _`enums`_ to generate response maps that can be used in
2831/// [`utoipa::path`][path_into_responses]. If _`struct`_ is decorated with [`derive@IntoResponses`] it will be
2832/// used to create a map of responses containing single response. Decorating _`enum`_ with
2833/// [`derive@IntoResponses`] will create a map of responses with a response for each variant of the _`enum`_.
2834///
2835/// Named field _`struct`_ decorated with [`derive@IntoResponses`] will create a response with inlined schema
2836/// generated from the body of the struct. This is a conveniency which allows users to directly
2837/// create responses with schemas without first creating a separate [response][to_response] type.
2838///
2839/// Unit _`struct`_ behaves similarly to then named field struct. Only difference is that it will create
2840/// a response without content since there is no inner fields.
2841///
2842/// Unnamed field _`struct`_ decorated with [`derive@IntoResponses`] will by default create a response with
2843/// referenced [schema][to_schema] if field is object or schema if type is [primitive
2844/// type][primitive]. _`#[to_schema]`_ attribute at field of unnamed _`struct`_ can be used to inline
2845/// the schema if type of the field implements [`ToSchema`][to_schema] trait. Alternatively
2846/// _`#[to_response]`_ and _`#[ref_response]`_ can be used at field to either reference a reusable
2847/// [response][to_response] or inline a reusable [response][to_response]. In both cases the field
2848/// type is expected to implement [`ToResponse`][to_response] trait.
2849///
2850///
2851/// Enum decorated with [`derive@IntoResponses`] will create a response for each variant of the _`enum`_.
2852/// Each variant must have it's own _`#[response(...)]`_ definition. Unit variant will behave same
2853/// as unit _`struct`_ by creating a response without content. Similarly named field variant and
2854/// unnamed field variant behaves the same as it was named field _`struct`_ and unnamed field
2855/// _`struct`_.
2856///
2857/// _`#[response]`_ attribute can be used at named structs, unnamed structs, unit structs and enum
2858/// variants to alter [response attributes](#intoresponses-response-attributes) of responses.
2859///
2860/// Doc comment on a _`struct`_ or _`enum`_ variant will be used as a description for the response.
2861/// It can also be overridden with _`description = "..."`_ attribute.
2862///
2863/// # IntoResponses `#[response(...)]` attributes
2864///
2865/// * `status = ...` Must be provided. Is either a valid http status code integer. E.g. _`200`_ or a
2866/// string value representing a range such as _`"4XX"`_ or `"default"` or a valid _`http::status::StatusCode`_.
2867/// _`StatusCode`_ can either be use path to the status code or _status code_ constant directly.
2868///
2869/// * `description = "..."` Define description for the response as str. This can be used to
2870/// override the default description resolved from doc comments if present.
2871///
2872/// * `content_type = "..."` Can be used to override the default behavior
2873/// of auto resolving the content type from the `body` attribute. If defined the value should be valid
2874/// content type such as _`application/json`_ . By default the content type is _`text/plain`_
2875/// for [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and _`application/json`_
2876/// for struct and mixed enum types.
2877///
2878/// * `headers(...)` Slice of response headers that are returned back to a caller.
2879///
2880/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
2881/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2882///
2883/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
2884/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
2885/// * `name = ...` This is first attribute and value must be literal string.
2886/// * `summary = ...` Short description of example. Value must be literal string.
2887/// * `description = ...` Long description of example. Attribute supports markdown for rich text
2888/// representation. Value must be literal string.
2889/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
2890/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2891/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
2892/// the _`value`_ attribute. Value must be literal string.
2893///
2894/// _**Example of example definition.**_
2895/// ```text
2896/// ("John" = (summary = "This is John", value = json!({"name": "John"})))
2897/// ```
2898///
2899/// # Examples
2900///
2901/// _**Use `IntoResponses` to define [`utoipa::path`][path] responses.**_
2902/// ```rust
2903/// #[derive(utoipa::ToSchema)]
2904/// struct BadRequest {
2905/// message: String,
2906/// }
2907///
2908/// #[derive(utoipa::IntoResponses)]
2909/// enum UserResponses {
2910/// /// Success response
2911/// #[response(status = 200)]
2912/// Success { value: String },
2913///
2914/// #[response(status = 404)]
2915/// NotFound,
2916///
2917/// #[response(status = 400)]
2918/// BadRequest(BadRequest),
2919/// }
2920///
2921/// #[utoipa::path(
2922/// get,
2923/// path = "/api/user",
2924/// responses(
2925/// UserResponses
2926/// )
2927/// )]
2928/// fn get_user() -> UserResponses {
2929/// UserResponses::NotFound
2930/// }
2931/// ```
2932/// _**Named struct response with inlined schema.**_
2933/// ```rust
2934/// /// This is success response
2935/// #[derive(utoipa::IntoResponses)]
2936/// #[response(status = 200)]
2937/// struct SuccessResponse {
2938/// value: String,
2939/// }
2940/// ```
2941///
2942/// _**Unit struct response without content.**_
2943/// ```rust
2944/// #[derive(utoipa::IntoResponses)]
2945/// #[response(status = NOT_FOUND)]
2946/// struct NotFound;
2947/// ```
2948///
2949/// _**Unnamed struct response with inlined response schema.**_
2950/// ```rust
2951/// # #[derive(utoipa::ToSchema)]
2952/// # struct Foo;
2953/// #[derive(utoipa::IntoResponses)]
2954/// #[response(status = 201)]
2955/// struct CreatedResponse(#[to_schema] Foo);
2956/// ```
2957///
2958/// _**Enum with multiple responses.**_
2959/// ```rust
2960/// # #[derive(utoipa::ToResponse)]
2961/// # struct Response {
2962/// # message: String,
2963/// # }
2964/// # #[derive(utoipa::ToSchema)]
2965/// # struct BadRequest {}
2966/// #[derive(utoipa::IntoResponses)]
2967/// enum UserResponses {
2968/// /// Success response description.
2969/// #[response(status = 200)]
2970/// Success { value: String },
2971///
2972/// #[response(status = 404)]
2973/// NotFound,
2974///
2975/// #[response(status = 400)]
2976/// BadRequest(BadRequest),
2977///
2978/// #[response(status = 500)]
2979/// ServerError(#[ref_response] Response),
2980///
2981/// #[response(status = 418)]
2982/// TeaPot(#[to_response] Response),
2983/// }
2984/// ```
2985///
2986/// [into_responses]: trait.IntoResponses.html
2987/// [to_schema]: trait.ToSchema.html
2988/// [to_response]: trait.ToResponse.html
2989/// [path_into_responses]: attr.path.html#responses-from-intoresponses
2990/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2991/// [path]: macro@crate::path
2992pub fn into_responses(input: TokenStream) -> TokenStream {
2993 let DeriveInput {
2994 attrs,
2995 ident,
2996 generics,
2997 data,
2998 ..
2999 } = syn::parse_macro_input!(input);
3000
3001 let into_responses = IntoResponses {
3002 attributes: attrs,
3003 ident,
3004 generics,
3005 data,
3006 };
3007
3008 into_responses.to_token_stream().into()
3009}
3010
3011/// Create OpenAPI Schema from arbitrary type.
3012///
3013/// This macro provides a quick way to render arbitrary types as OpenAPI Schema Objects. It
3014/// supports two call formats.
3015/// 1. With type only
3016/// 2. With _`#[inline]`_ attribute to inline the referenced schemas.
3017///
3018/// By default the macro will create references `($ref)` for non primitive types like _`Pet`_.
3019/// However when used with _`#[inline]`_ the non [`primitive`][primitive] type schemas will
3020/// be inlined to the schema output.
3021///
3022/// ```rust
3023/// # use utoipa::openapi::{RefOr, schema::Schema};
3024/// # #[derive(utoipa::ToSchema)]
3025/// # struct Pet {id: i32};
3026/// let schema: RefOr<Schema> = utoipa::schema!(Vec<Pet>).into();
3027///
3028/// // with inline
3029/// let schema: RefOr<Schema> = utoipa::schema!(#[inline] Vec<Pet>).into();
3030/// ```
3031///
3032/// # Examples
3033///
3034/// _**Create vec of pets schema.**_
3035/// ```rust
3036/// # use utoipa::openapi::schema::{Schema, Array, Object, ObjectBuilder, SchemaFormat,
3037/// # KnownFormat, Type};
3038/// # use utoipa::openapi::RefOr;
3039/// #[derive(utoipa::ToSchema)]
3040/// struct Pet {
3041/// id: i32,
3042/// name: String,
3043/// }
3044///
3045/// let schema: RefOr<Schema> = utoipa::schema!(#[inline] Vec<Pet>).into();
3046/// // will output
3047/// let generated = RefOr::T(Schema::Array(
3048/// Array::new(
3049/// ObjectBuilder::new()
3050/// .property("id", ObjectBuilder::new()
3051/// .schema_type(Type::Integer)
3052/// .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
3053/// .build())
3054/// .required("id")
3055/// .property("name", Object::with_type(Type::String))
3056/// .required("name")
3057/// )
3058/// ));
3059/// # insta::assert_json_snapshot!("schema", &schema);
3060/// ```
3061///
3062/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
3063#[proc_macro]
3064pub fn schema(input: TokenStream) -> TokenStream {
3065 struct Schema {
3066 inline: bool,
3067 ty: syn::Type,
3068 }
3069 impl Parse for Schema {
3070 fn parse(input: ParseStream) -> syn::Result<Self> {
3071 let inline = if input.peek(Token![#]) && input.peek2(Bracket) {
3072 input.parse::<Token![#]>()?;
3073
3074 let inline;
3075 bracketed!(inline in input);
3076 let i = inline.parse::<Ident>()?;
3077 i == "inline"
3078 } else {
3079 false
3080 };
3081
3082 let ty = input.parse()?;
3083
3084 Ok(Self { inline, ty })
3085 }
3086 }
3087
3088 let schema = syn::parse_macro_input!(input as Schema);
3089 let type_tree = match TypeTree::from_type(&schema.ty) {
3090 Ok(type_tree) => type_tree,
3091 Err(diagnostics) => return diagnostics.into_token_stream().into(),
3092 };
3093
3094 let generics = match type_tree.get_path_generics() {
3095 Ok(generics) => generics,
3096 Err(error) => return error.into_compile_error().into(),
3097 };
3098
3099 let schema = ComponentSchema::new(ComponentSchemaProps {
3100 features: vec![Feature::Inline(schema.inline.into())],
3101 type_tree: &type_tree,
3102 description: None,
3103 container: &component::Container {
3104 generics: &generics,
3105 },
3106 });
3107
3108 let schema = match schema {
3109 Ok(schema) => schema.to_token_stream(),
3110 Err(diagnostics) => return diagnostics.to_token_stream().into(),
3111 };
3112
3113 quote! {
3114 {
3115 let mut generics: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>> = Vec::new();
3116 #schema
3117 }
3118 }
3119 .into()
3120}
3121
3122/// Tokenizes slice or Vec of tokenizable items as array either with reference (`&[...]`)
3123/// or without correctly to OpenAPI JSON.
3124#[cfg_attr(feature = "debug", derive(Debug))]
3125enum Array<'a, T>
3126where
3127 T: Sized + ToTokens,
3128{
3129 Owned(Vec<T>),
3130 #[allow(dead_code)]
3131 Borrowed(&'a [T]),
3132}
3133
3134impl<V> FromIterator<V> for Array<'_, V>
3135where
3136 V: Sized + ToTokens,
3137{
3138 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
3139 Self::Owned(iter.into_iter().collect())
3140 }
3141}
3142
3143impl<'a, T> Deref for Array<'a, T>
3144where
3145 T: Sized + ToTokens,
3146{
3147 type Target = [T];
3148
3149 fn deref(&self) -> &Self::Target {
3150 match self {
3151 Self::Owned(vec) => vec.as_slice(),
3152 Self::Borrowed(slice) => slice,
3153 }
3154 }
3155}
3156
3157impl<T> ToTokens for Array<'_, T>
3158where
3159 T: Sized + ToTokens,
3160{
3161 fn to_tokens(&self, tokens: &mut TokenStream2) {
3162 let values = match self {
3163 Self::Owned(values) => values.iter(),
3164 Self::Borrowed(values) => values.iter(),
3165 };
3166
3167 tokens.append(Group::new(
3168 proc_macro2::Delimiter::Bracket,
3169 values
3170 .fold(Punctuated::new(), |mut punctuated, item| {
3171 punctuated.push_value(item);
3172 punctuated.push_punct(Punct::new(',', proc_macro2::Spacing::Alone));
3173
3174 punctuated
3175 })
3176 .to_token_stream(),
3177 ));
3178 }
3179}
3180
3181#[cfg_attr(feature = "debug", derive(Debug))]
3182enum Deprecated {
3183 True,
3184 False,
3185}
3186
3187impl From<bool> for Deprecated {
3188 fn from(bool: bool) -> Self {
3189 if bool {
3190 Self::True
3191 } else {
3192 Self::False
3193 }
3194 }
3195}
3196
3197impl ToTokens for Deprecated {
3198 fn to_tokens(&self, tokens: &mut TokenStream2) {
3199 tokens.extend(match self {
3200 Self::False => quote! { utoipa::openapi::Deprecated::False },
3201 Self::True => quote! { utoipa::openapi::Deprecated::True },
3202 })
3203 }
3204}
3205
3206#[derive(PartialEq, Eq)]
3207#[cfg_attr(feature = "debug", derive(Debug))]
3208enum Required {
3209 True,
3210 False,
3211}
3212
3213impl From<bool> for Required {
3214 fn from(bool: bool) -> Self {
3215 if bool {
3216 Self::True
3217 } else {
3218 Self::False
3219 }
3220 }
3221}
3222
3223impl From<features::attributes::Required> for Required {
3224 fn from(value: features::attributes::Required) -> Self {
3225 let features::attributes::Required(required) = value;
3226 crate::Required::from(required)
3227 }
3228}
3229
3230impl ToTokens for Required {
3231 fn to_tokens(&self, tokens: &mut TokenStream2) {
3232 tokens.extend(match self {
3233 Self::False => quote! { utoipa::openapi::Required::False },
3234 Self::True => quote! { utoipa::openapi::Required::True },
3235 })
3236 }
3237}
3238
3239#[derive(Default)]
3240#[cfg_attr(feature = "debug", derive(Debug))]
3241struct ExternalDocs {
3242 url: String,
3243 description: Option<String>,
3244}
3245
3246impl Parse for ExternalDocs {
3247 fn parse(input: ParseStream) -> syn::Result<Self> {
3248 const EXPECTED_ATTRIBUTE: &str = "unexpected attribute, expected any of: url, description";
3249
3250 let mut external_docs = ExternalDocs::default();
3251
3252 while !input.is_empty() {
3253 let ident = input.parse::<Ident>().map_err(|error| {
3254 syn::Error::new(error.span(), format!("{EXPECTED_ATTRIBUTE}, {error}"))
3255 })?;
3256 let attribute_name = &*ident.to_string();
3257
3258 match attribute_name {
3259 "url" => {
3260 external_docs.url = parse_utils::parse_next_literal_str(input)?;
3261 }
3262 "description" => {
3263 external_docs.description = Some(parse_utils::parse_next_literal_str(input)?);
3264 }
3265 _ => return Err(syn::Error::new(ident.span(), EXPECTED_ATTRIBUTE)),
3266 }
3267
3268 if !input.is_empty() {
3269 input.parse::<Token![,]>()?;
3270 }
3271 }
3272
3273 Ok(external_docs)
3274 }
3275}
3276
3277impl ToTokens for ExternalDocs {
3278 fn to_tokens(&self, tokens: &mut TokenStream2) {
3279 let url = &self.url;
3280 tokens.extend(quote! {
3281 utoipa::openapi::external_docs::ExternalDocsBuilder::new()
3282 .url(#url)
3283 });
3284
3285 if let Some(ref description) = self.description {
3286 tokens.extend(quote! {
3287 .description(Some(#description))
3288 });
3289 }
3290
3291 tokens.extend(quote! { .build() })
3292 }
3293}
3294
3295/// Represents OpenAPI Any value used in example and default fields.
3296#[derive(Clone)]
3297#[cfg_attr(feature = "debug", derive(Debug))]
3298enum AnyValue {
3299 String(TokenStream2),
3300 Json(TokenStream2),
3301 DefaultTrait {
3302 struct_ident: Ident,
3303 field_ident: Member,
3304 },
3305}
3306
3307impl AnyValue {
3308 /// Parse `json!(...)` as [`AnyValue::Json`]
3309 fn parse_json(input: ParseStream) -> syn::Result<Self> {
3310 parse_utils::parse_json_token_stream(input).map(AnyValue::Json)
3311 }
3312
3313 fn parse_any(input: ParseStream) -> syn::Result<Self> {
3314 if input.peek(Lit) {
3315 let punct = input.parse::<Option<Token![-]>>()?;
3316 let lit = input.parse::<Lit>().unwrap();
3317
3318 Ok(AnyValue::Json(quote! { #punct #lit}))
3319 } else {
3320 let fork = input.fork();
3321 let is_json = if fork.peek(syn::Ident) && fork.peek2(Token![!]) {
3322 let ident = fork.parse::<Ident>().unwrap();
3323 ident == "json"
3324 } else {
3325 false
3326 };
3327
3328 if is_json {
3329 let json = parse_utils::parse_json_token_stream(input)?;
3330
3331 Ok(AnyValue::Json(json))
3332 } else {
3333 let method = input.parse::<ExprPath>().map_err(|error| {
3334 syn::Error::new(
3335 error.span(),
3336 "expected literal value, json!(...) or method reference",
3337 )
3338 })?;
3339
3340 Ok(AnyValue::Json(quote! { #method() }))
3341 }
3342 }
3343 }
3344
3345 fn parse_lit_str_or_json(input: ParseStream) -> syn::Result<Self> {
3346 if input.peek(LitStr) {
3347 Ok(AnyValue::String(
3348 input.parse::<LitStr>().unwrap().to_token_stream(),
3349 ))
3350 } else {
3351 Ok(AnyValue::Json(parse_utils::parse_json_token_stream(input)?))
3352 }
3353 }
3354
3355 fn new_default_trait(struct_ident: Ident, field_ident: Member) -> Self {
3356 Self::DefaultTrait {
3357 struct_ident,
3358 field_ident,
3359 }
3360 }
3361}
3362
3363impl ToTokens for AnyValue {
3364 fn to_tokens(&self, tokens: &mut TokenStream2) {
3365 match self {
3366 Self::Json(json) => tokens.extend(quote! {
3367 utoipa::gen::serde_json::json!(#json)
3368 }),
3369 Self::String(string) => string.to_tokens(tokens),
3370 Self::DefaultTrait {
3371 struct_ident,
3372 field_ident,
3373 } => tokens.extend(quote! {
3374 utoipa::gen::serde_json::to_value(#struct_ident::default().#field_ident).unwrap()
3375 }),
3376 }
3377 }
3378}
3379
3380trait OptionExt<T> {
3381 fn map_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3382 where
3383 F: FnOnce(T) -> Result<U, E>;
3384 fn and_then_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3385 where
3386 F: FnOnce(T) -> Result<Option<U>, E>;
3387 fn or_else_try<F, U>(self, f: F) -> Result<Option<T>, U>
3388 where
3389 F: FnOnce() -> Result<Option<T>, U>;
3390}
3391
3392impl<T> OptionExt<T> for Option<T> {
3393 fn map_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3394 where
3395 F: FnOnce(T) -> Result<U, E>,
3396 {
3397 if let Some(v) = self {
3398 f(v).map(Some)
3399 } else {
3400 Ok(None)
3401 }
3402 }
3403
3404 fn and_then_try<F, U, E>(self, f: F) -> Result<Option<U>, E>
3405 where
3406 F: FnOnce(T) -> Result<Option<U>, E>,
3407 {
3408 if let Some(v) = self {
3409 match f(v) {
3410 Ok(inner) => Ok(inner),
3411 Err(error) => Err(error),
3412 }
3413 } else {
3414 Ok(None)
3415 }
3416 }
3417
3418 fn or_else_try<F, U>(self, f: F) -> Result<Option<T>, U>
3419 where
3420 F: FnOnce() -> Result<Option<T>, U>,
3421 {
3422 if self.is_none() {
3423 f()
3424 } else {
3425 Ok(self)
3426 }
3427 }
3428}
3429
3430trait GenericsExt {
3431 /// Get index of `GenericParam::Type` ignoring other generic param types.
3432 fn get_generic_type_param_index(&self, type_tree: &TypeTree) -> Option<usize>;
3433}
3434
3435impl<'g> GenericsExt for &'g syn::Generics {
3436 fn get_generic_type_param_index(&self, type_tree: &TypeTree) -> Option<usize> {
3437 let ident = &type_tree
3438 .path
3439 .as_ref()
3440 .expect("TypeTree of generic object must have a path")
3441 .segments
3442 .last()
3443 .expect("Generic object path must have at least one segment")
3444 .ident;
3445
3446 self.params
3447 .iter()
3448 .filter(|generic| matches!(generic, GenericParam::Type(_)))
3449 .enumerate()
3450 .find_map(|(index, generic)| {
3451 if matches!(generic, GenericParam::Type(ty) if ty.ident == *ident) {
3452 Some(index)
3453 } else {
3454 None
3455 }
3456 })
3457 }
3458}
3459
3460trait ToTokensDiagnostics {
3461 fn to_tokens(&self, tokens: &mut TokenStream2) -> Result<(), Diagnostics>;
3462
3463 #[allow(unused)]
3464 fn into_token_stream(self) -> TokenStream2
3465 where
3466 Self: std::marker::Sized,
3467 {
3468 ToTokensDiagnostics::to_token_stream(&self)
3469 }
3470
3471 fn to_token_stream(&self) -> TokenStream2 {
3472 let mut tokens = TokenStream2::new();
3473 match ToTokensDiagnostics::to_tokens(self, &mut tokens) {
3474 Ok(_) => tokens,
3475 Err(error_stream) => Into::<Diagnostics>::into(error_stream).into_token_stream(),
3476 }
3477 }
3478
3479 fn try_to_token_stream(&self) -> Result<TokenStream2, Diagnostics> {
3480 let mut tokens = TokenStream2::new();
3481 match ToTokensDiagnostics::to_tokens(self, &mut tokens) {
3482 Ok(_) => Ok(tokens),
3483 Err(diagnostics) => Err(diagnostics),
3484 }
3485 }
3486}
3487
3488macro_rules! as_tokens_or_diagnostics {
3489 ( $type:expr ) => {{
3490 let mut _tokens = proc_macro2::TokenStream::new();
3491 match crate::ToTokensDiagnostics::to_tokens($type, &mut _tokens) {
3492 Ok(_) => _tokens,
3493 Err(diagnostics) => return Err(diagnostics),
3494 }
3495 }};
3496}
3497
3498use as_tokens_or_diagnostics;
3499
3500#[derive(Debug)]
3501struct Diagnostics {
3502 diagnostics: Vec<DiangosticsInner>,
3503}
3504
3505#[derive(Debug)]
3506struct DiangosticsInner {
3507 span: Span,
3508 message: Cow<'static, str>,
3509 suggestions: Vec<Suggestion>,
3510}
3511
3512#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
3513enum Suggestion {
3514 Help(Cow<'static, str>),
3515 Note(Cow<'static, str>),
3516}
3517
3518impl Display for Diagnostics {
3519 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3520 write!(f, "{}", self.message())
3521 }
3522}
3523
3524impl Display for Suggestion {
3525 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3526 match self {
3527 Self::Help(help) => {
3528 let s: &str = help.borrow();
3529 write!(f, "help = {}", s)
3530 }
3531 Self::Note(note) => {
3532 let s: &str = note.borrow();
3533 write!(f, "note = {}", s)
3534 }
3535 }
3536 }
3537}
3538
3539impl Diagnostics {
3540 fn message(&self) -> Cow<'static, str> {
3541 self.diagnostics
3542 .first()
3543 .as_ref()
3544 .map(|diagnostics| diagnostics.message.clone())
3545 .unwrap_or_else(|| Cow::Borrowed(""))
3546 }
3547
3548 pub fn new<S: Into<Cow<'static, str>>>(message: S) -> Self {
3549 Self::with_span(Span::call_site(), message)
3550 }
3551
3552 pub fn with_span<S: Into<Cow<'static, str>>>(span: Span, message: S) -> Self {
3553 Self {
3554 diagnostics: vec![DiangosticsInner {
3555 span,
3556 message: message.into(),
3557 suggestions: Vec::new(),
3558 }],
3559 }
3560 }
3561
3562 pub fn help<S: Into<Cow<'static, str>>>(mut self, help: S) -> Self {
3563 if let Some(diagnostics) = self.diagnostics.first_mut() {
3564 diagnostics.suggestions.push(Suggestion::Help(help.into()));
3565 diagnostics.suggestions.sort();
3566 }
3567
3568 self
3569 }
3570
3571 pub fn note<S: Into<Cow<'static, str>>>(mut self, note: S) -> Self {
3572 if let Some(diagnostics) = self.diagnostics.first_mut() {
3573 diagnostics.suggestions.push(Suggestion::Note(note.into()));
3574 diagnostics.suggestions.sort();
3575 }
3576
3577 self
3578 }
3579}
3580
3581impl From<syn::Error> for Diagnostics {
3582 fn from(value: syn::Error) -> Self {
3583 Self::with_span(value.span(), value.to_string())
3584 }
3585}
3586
3587impl ToTokens for Diagnostics {
3588 fn to_tokens(&self, tokens: &mut TokenStream2) {
3589 for diagnostics in &self.diagnostics {
3590 let span = diagnostics.span;
3591 let message: &str = diagnostics.message.borrow();
3592
3593 let suggestions = diagnostics
3594 .suggestions
3595 .iter()
3596 .map(Suggestion::to_string)
3597 .collect::<Vec<_>>()
3598 .join("\n");
3599
3600 let diagnostics = if !suggestions.is_empty() {
3601 Cow::Owned(format!("{message}\n\n{suggestions}"))
3602 } else {
3603 Cow::Borrowed(message)
3604 };
3605
3606 tokens.extend(quote_spanned! {span=>
3607 ::core::compile_error!(#diagnostics);
3608 })
3609 }
3610 }
3611}
3612
3613impl Error for Diagnostics {}
3614
3615impl FromIterator<Diagnostics> for Option<Diagnostics> {
3616 fn from_iter<T: IntoIterator<Item = Diagnostics>>(iter: T) -> Self {
3617 iter.into_iter().reduce(|mut acc, diagnostics| {
3618 acc.diagnostics.extend(diagnostics.diagnostics);
3619 acc
3620 })
3621 }
3622}
3623
3624trait AttributesExt {
3625 fn has_deprecated(&self) -> bool;
3626}
3627
3628impl AttributesExt for Vec<syn::Attribute> {
3629 fn has_deprecated(&self) -> bool {
3630 let this = &**self;
3631 this.has_deprecated()
3632 }
3633}
3634
3635impl<'a> AttributesExt for &'a [syn::Attribute] {
3636 fn has_deprecated(&self) -> bool {
3637 self.iter().any(|attr| {
3638 matches!(attr.path().get_ident(), Some(ident) if &*ident.to_string() == "deprecated")
3639 })
3640 }
3641}
3642
3643#[cfg(test)]
3644mod tests {
3645 use super::*;
3646
3647 #[test]
3648 fn diagnostics_ordering_help_comes_before_note() {
3649 let diagnostics = Diagnostics::new("this an error")
3650 .note("you could do this to solve the error")
3651 .help("try this thing");
3652
3653 let tokens = diagnostics.into_token_stream();
3654
3655 let expected_tokens = quote::quote!(::core::compile_error!(
3656 "this an error\n\nhelp = try this thing\nnote = you could do this to solve the error"
3657 ););
3658
3659 assert_eq!(tokens.to_string(), expected_tokens.to_string());
3660 }
3661}
3662
3663/// Parsing utils
3664mod parse_utils {
3665 use std::fmt::Display;
3666
3667 use proc_macro2::{Group, Ident, TokenStream};
3668 use quote::{quote, ToTokens};
3669 use syn::{
3670 parenthesized,
3671 parse::{Parse, ParseStream},
3672 punctuated::Punctuated,
3673 spanned::Spanned,
3674 token::Comma,
3675 Error, Expr, ExprPath, LitBool, LitStr, Token,
3676 };
3677
3678 #[cfg_attr(feature = "debug", derive(Debug))]
3679 #[derive(Clone)]
3680 pub enum LitStrOrExpr {
3681 LitStr(LitStr),
3682 Expr(Expr),
3683 }
3684
3685 impl From<String> for LitStrOrExpr {
3686 fn from(value: String) -> Self {
3687 Self::LitStr(LitStr::new(&value, proc_macro2::Span::call_site()))
3688 }
3689 }
3690
3691 impl LitStrOrExpr {
3692 pub(crate) fn is_empty_litstr(&self) -> bool {
3693 matches!(self, Self::LitStr(s) if s.value().is_empty())
3694 }
3695 }
3696
3697 impl Default for LitStrOrExpr {
3698 fn default() -> Self {
3699 Self::LitStr(LitStr::new("", proc_macro2::Span::call_site()))
3700 }
3701 }
3702
3703 impl Parse for LitStrOrExpr {
3704 fn parse(input: ParseStream) -> syn::Result<Self> {
3705 if input.peek(LitStr) {
3706 Ok::<LitStrOrExpr, Error>(LitStrOrExpr::LitStr(input.parse::<LitStr>()?))
3707 } else {
3708 Ok(LitStrOrExpr::Expr(input.parse::<Expr>()?))
3709 }
3710 }
3711 }
3712
3713 impl ToTokens for LitStrOrExpr {
3714 fn to_tokens(&self, tokens: &mut TokenStream) {
3715 match self {
3716 Self::LitStr(str) => str.to_tokens(tokens),
3717 Self::Expr(expr) => expr.to_tokens(tokens),
3718 }
3719 }
3720 }
3721
3722 impl Display for LitStrOrExpr {
3723 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3724 match self {
3725 Self::LitStr(str) => write!(f, "{str}", str = str.value()),
3726 Self::Expr(expr) => write!(f, "{expr}", expr = expr.into_token_stream()),
3727 }
3728 }
3729 }
3730
3731 pub fn parse_next<T: FnOnce() -> Result<R, syn::Error>, R: Sized>(
3732 input: ParseStream,
3733 next: T,
3734 ) -> Result<R, syn::Error> {
3735 input.parse::<Token![=]>()?;
3736 next()
3737 }
3738
3739 pub fn parse_next_literal_str(input: ParseStream) -> syn::Result<String> {
3740 Ok(parse_next(input, || input.parse::<LitStr>())?.value())
3741 }
3742
3743 pub fn parse_next_literal_str_or_expr(input: ParseStream) -> syn::Result<LitStrOrExpr> {
3744 parse_next(input, || LitStrOrExpr::parse(input)).map_err(|error| {
3745 syn::Error::new(
3746 error.span(),
3747 format!("expected literal string or expression argument: {error}"),
3748 )
3749 })
3750 }
3751
3752 pub fn parse_groups_collect<T, R>(input: ParseStream) -> syn::Result<R>
3753 where
3754 T: Sized,
3755 T: Parse,
3756 R: FromIterator<T>,
3757 {
3758 Punctuated::<Group, Comma>::parse_terminated(input).and_then(|groups| {
3759 groups
3760 .into_iter()
3761 .map(|group| syn::parse2::<T>(group.stream()))
3762 .collect::<syn::Result<R>>()
3763 })
3764 }
3765
3766 pub fn parse_parethesized_terminated<T: Parse, S: Parse>(
3767 input: ParseStream,
3768 ) -> syn::Result<Punctuated<T, S>> {
3769 let group;
3770 syn::parenthesized!(group in input);
3771 Punctuated::parse_terminated(&group)
3772 }
3773
3774 pub fn parse_comma_separated_within_parethesis_with<T>(
3775 input: ParseStream,
3776 with: fn(ParseStream) -> syn::Result<T>,
3777 ) -> syn::Result<Punctuated<T, Comma>>
3778 where
3779 T: Parse,
3780 {
3781 let content;
3782 parenthesized!(content in input);
3783 Punctuated::<T, Comma>::parse_terminated_with(&content, with)
3784 }
3785
3786 pub fn parse_comma_separated_within_parenthesis<T>(
3787 input: ParseStream,
3788 ) -> syn::Result<Punctuated<T, Comma>>
3789 where
3790 T: Parse,
3791 {
3792 let content;
3793 parenthesized!(content in input);
3794 Punctuated::<T, Comma>::parse_terminated(&content)
3795 }
3796
3797 pub fn parse_bool_or_true(input: ParseStream) -> syn::Result<bool> {
3798 if input.peek(Token![=]) && input.peek2(LitBool) {
3799 input.parse::<Token![=]>()?;
3800
3801 Ok(input.parse::<LitBool>()?.value())
3802 } else {
3803 Ok(true)
3804 }
3805 }
3806
3807 /// Parse `json!(...)` as a [`TokenStream`].
3808 pub fn parse_json_token_stream(input: ParseStream) -> syn::Result<TokenStream> {
3809 if input.peek(syn::Ident) && input.peek2(Token![!]) {
3810 input.parse::<Ident>().and_then(|ident| {
3811 if ident != "json" {
3812 return Err(Error::new(
3813 ident.span(),
3814 format!("unexpected token {ident}, expected: json!(...)"),
3815 ));
3816 }
3817
3818 Ok(ident)
3819 })?;
3820 input.parse::<Token![!]>()?;
3821
3822 Ok(input.parse::<Group>()?.stream())
3823 } else {
3824 Err(Error::new(
3825 input.span(),
3826 "unexpected token, expected json!(...)",
3827 ))
3828 }
3829 }
3830
3831 #[cfg_attr(feature = "debug", derive(Debug))]
3832 #[derive(Clone)]
3833 pub enum LitBoolOrExprPath {
3834 LitBool(LitBool),
3835 ExprPath(ExprPath),
3836 }
3837
3838 impl From<bool> for LitBoolOrExprPath {
3839 fn from(value: bool) -> Self {
3840 Self::LitBool(LitBool::new(value, proc_macro2::Span::call_site()))
3841 }
3842 }
3843
3844 impl Default for LitBoolOrExprPath {
3845 fn default() -> Self {
3846 Self::LitBool(LitBool::new(false, proc_macro2::Span::call_site()))
3847 }
3848 }
3849
3850 impl Parse for LitBoolOrExprPath {
3851 fn parse(input: ParseStream) -> syn::Result<Self> {
3852 if input.peek(LitBool) {
3853 Ok(LitBoolOrExprPath::LitBool(input.parse::<LitBool>()?))
3854 } else {
3855 let expr = input.parse::<Expr>()?;
3856
3857 match expr {
3858 Expr::Path(expr_path) => Ok(LitBoolOrExprPath::ExprPath(expr_path)),
3859 _ => Err(syn::Error::new(
3860 expr.span(),
3861 format!(
3862 "expected literal bool or path to a function that returns bool, found: {}",
3863 quote! {#expr}
3864 ),
3865 )),
3866 }
3867 }
3868 }
3869 }
3870
3871 impl ToTokens for LitBoolOrExprPath {
3872 fn to_tokens(&self, tokens: &mut TokenStream) {
3873 match self {
3874 Self::LitBool(bool) => bool.to_tokens(tokens),
3875 Self::ExprPath(call) => call.to_tokens(tokens),
3876 }
3877 }
3878 }
3879
3880 pub fn parse_next_literal_bool_or_call(input: ParseStream) -> syn::Result<LitBoolOrExprPath> {
3881 if input.peek(Token![=]) {
3882 parse_next(input, || LitBoolOrExprPath::parse(input))
3883 } else {
3884 Ok(LitBoolOrExprPath::from(true))
3885 }
3886 }
3887}