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