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