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#![warn(missing_docs)]
8#![warn(rustdoc::broken_intra_doc_links)]
9
10use std::{mem, ops::Deref};
11
12use component::schema::Schema;
13use doc_comment::CommentAttributes;
14
15use component::into_params::IntoParams;
16use ext::{PathOperationResolver, PathOperations, PathResolver};
17use openapi::OpenApi;
18use proc_macro::TokenStream;
19use proc_macro_error::{abort, proc_macro_error};
20use quote::{quote, ToTokens, TokenStreamExt};
21
22use proc_macro2::{Group, Ident, Punct, Span, TokenStream as TokenStream2};
23use syn::{
24 bracketed,
25 parse::{Parse, ParseStream},
26 punctuated::Punctuated,
27 token::Bracket,
28 DeriveInput, ExprPath, ItemFn, Lit, LitStr, Member, Token,
29};
30
31mod component;
32mod doc_comment;
33mod ext;
34mod openapi;
35mod path;
36mod schema_type;
37mod security_requirement;
38
39use crate::path::{Path, PathAttr};
40
41use self::{
42 component::{
43 features::{self, Feature},
44 ComponentSchema, ComponentSchemaProps, TypeTree,
45 },
46 path::response::derive::{IntoResponses, ToResponse},
47};
48
49#[proc_macro_error]
50#[proc_macro_derive(ToSchema, attributes(schema, aliases))]
51/// Generate reusable OpenAPI schema to be used
52/// together with [`OpenApi`][openapi_derive].
53///
54/// This is `#[derive]` implementation for [`ToSchema`][to_schema] trait. The macro accepts one
55/// `schema`
56/// attribute optionally which can be used to enhance generated documentation. The attribute can be placed
57/// at item level or field level in struct and enums. Currently placing this attribute to unnamed field does
58/// not have any effect.
59///
60/// You can use the Rust's own `#[deprecated]` attribute on any struct, enum or field to mark it as deprecated and it will
61/// reflect to the generated OpenAPI spec.
62///
63/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version but this is is not supported in
64/// OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
65/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
66///
67/// Doc comments on fields will resolve to field descriptions in generated OpenAPI doc. On struct
68/// level doc comments will resolve to object descriptions.
69///
70/// ```rust
71/// /// This is a pet
72/// #[derive(utoipa::ToSchema)]
73/// struct Pet {
74/// /// Name for your pet
75/// name: String,
76/// }
77/// ```
78///
79/// # Struct Optional Configuration Options for `#[schema(...)]`
80/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
81/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
82/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to Structs.
83/// * `title = ...` Literal string value. Can be used to define title for struct in OpenAPI
84/// document. Some OpenAPI code generation libraries also use this field as a name for the
85/// struct.
86/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all fields
87/// of the structs accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_ are defined
88/// __serde__ will take precedence.
89/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
90/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
91/// OpenAPI spec as _`path.to.Pet`_.
92/// * `default` Can be used to populate default values on all fields using the struct's
93/// [`Default`](std::default::Default) implementation.
94/// * `deprecated` Can be used to mark all fields as deprecated in the generated OpenAPI spec but
95/// not in the code. If you'd like to mark the fields as deprecated in the code as well use
96/// Rust's own `#[deprecated]` attribute instead.
97
98/// # Enum Optional Configuration Options for `#[schema(...)]`
99/// * `example = ...` Can be method reference or _`json!(...)`_.
100/// * `default = ...` Can be method reference or _`json!(...)`_.
101/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
102/// document. Some OpenAPI code generation libraries also use this field as a name for the
103/// enum. __Note!__ ___Complex enum (enum with other than unit variants) does not support title!___
104/// * `rename_all = ...` Supports same syntax as _serde_ _`rename_all`_ attribute. Will rename all
105/// variants of the enum accordingly. If both _serde_ `rename_all` and _schema_ _`rename_all`_
106/// are defined __serde__ will take precedence.
107/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
108/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
109/// OpenAPI spec as _`path.to.Pet`_.
110/// * `deprecated` Can be used to mark the enum as deprecated in the generated OpenAPI spec but
111/// not in the code. If you'd like to mark the enum as deprecated in the code as well use
112/// Rust's own `#[deprecated]` attribute instead.
113///
114/// # Enum Variant Optional Configuration Options for `#[schema(...)]`
115/// Supports all variant specific configuration options e.g. if variant is _`UnnamedStruct`_ then
116/// unnamed struct type configuration options are supported.
117///
118/// In addition to the variant type specific configuration options enum variants support custom
119/// _`rename`_ attribute. It behaves similarly to serde's _`rename`_ attribute. If both _serde_
120/// _`rename`_ and _schema_ _`rename`_ are defined __serde__ will take precedence.
121///
122/// # Unnamed Field Struct Optional Configuration Options for `#[schema(...)]`
123/// * `example = ...` Can be method reference or _`json!(...)`_.
124/// * `default = ...` Can be method reference or _`json!(...)`_. If no value is specified, and the struct has
125/// only one field, the field's default value in the schema will be set from the struct's
126/// [`Default`](std::default::Default) implementation.
127/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
128/// an open value as a string. By default the format is derived from the type of the property
129/// according OpenApi spec.
130/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
131/// This is useful in cases where the default type does not correspond to the actual type e.g. when
132/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
133/// The value can be any Rust type what normally could be used to serialize to JSON or either virtual type _`Object`_
134/// or _`Value`_, or an alias defined using `#[aliases(..)]`.
135/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
136/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
137/// * `title = ...` Literal string value. Can be used to define title for struct in OpenAPI
138/// document. Some OpenAPI code generation libraries also use this field as a name for the
139/// struct.
140/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
141/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
142/// OpenAPI spec as _`path.to.Pet`_.
143/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
144/// not in the code. If you'd like to mark the field as deprecated in the code as well use
145/// Rust's own `#[deprecated]` attribute instead.
146///
147/// # Named Fields Optional Configuration Options for `#[schema(...)]`
148/// * `example = ...` Can be method reference or _`json!(...)`_.
149/// * `default = ...` Can be method reference or _`json!(...)`_.
150/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
151/// an open value as a string. By default the format is derived from the type of the property
152/// according OpenApi spec.
153/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
154/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
155/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to named fields.
156/// See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
157/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
158/// This is useful in cases where the default type does not correspond to the actual type e.g. when
159/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
160/// The value can be any Rust type what normally could be used to serialize to JSON, or either virtual type _`Object`_
161/// or _`Value`_, or an alias defined using `#[aliases(..)]`.
162/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
163/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
164/// * `inline` If the type of this field implements [`ToSchema`][to_schema], then the schema definition
165/// will be inlined. **warning:** Don't use this for recursive data types!
166/// * `required = ...` Can be used to enforce required status for the field. [See
167/// rules][derive@ToSchema#field-nullability-and-required-rules]
168/// * `nullable` Defines property is nullable (note this is different to non-required).
169/// * `rename = ...` Supports same syntax as _serde_ _`rename`_ attribute. Will rename field
170/// accordingly. If both _serde_ `rename` and _schema_ _`rename`_ are defined __serde__ will take
171/// precedence.
172/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
173/// division will result an `integer`. Value must be strictly above _`0`_.
174/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
175/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
176/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
177/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
178/// * `max_length = ...` Can be used to define maximum length for `string` types.
179/// * `min_length = ...` Can be used to define minimum length for `string` types.
180/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
181/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
182/// be non-negative integer.
183/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
184/// be non-negative integer.
185/// * `schema_with = ...` Use _`schema`_ created by provided function reference instead of the
186/// default derived _`schema`_. The function must match to `fn() -> Into<RefOr<Schema>>`. It does
187/// not accept arguments and must return anything that can be converted into `RefOr<Schema>`.
188/// * `additional_properties = ...` Can be used to define free form types for maps such as
189/// [`HashMap`](std::collections::HashMap) and [`BTreeMap`](std::collections::BTreeMap).
190/// Free form type enables use of arbitrary types within map values.
191/// Supports formats _`additional_properties`_ and _`additional_properties = true`_.
192/// * `deprecated` Can be used to mark the field as deprecated in the generated OpenAPI spec but
193/// not in the code. If you'd like to mark the field as deprecated in the code as well use
194/// Rust's own `#[deprecated]` attribute instead.
195///
196/// #### Field nullability and required rules
197///
198/// Field is considered _`required`_ if
199/// * it is not `Option` field
200/// * and it does not have _`skip_serializing_if`_ property
201/// * and it does not have _`serde_with`_ _[`double_option`](https://docs.rs/serde_with/latest/serde_with/rust/double_option/index.html)_
202/// * and it does not have default value provided with serde _`default`_
203/// attribute
204///
205/// Field is considered _`nullable`_ when field type is _`Option`_.
206///
207/// ## Xml attribute Configuration Options
208///
209/// * `xml(name = "...")` Will set name for property or type.
210/// * `xml(namespace = "...")` Will set namespace for xml element which needs to be valid uri.
211/// * `xml(prefix = "...")` Will set prefix for name.
212/// * `xml(attribute)` Will translate property to xml attribute instead of xml element.
213/// * `xml(wrapped)` Will make wrapped xml element.
214/// * `xml(wrapped(name = "wrap_name"))` Will override the wrapper elements name.
215///
216/// See [`Xml`][xml] for more details.
217///
218/// # Partial `#[serde(...)]` attributes support
219///
220/// ToSchema derive has partial support for [serde attributes]. These supported attributes will reflect to the
221/// 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
222/// be serialized anyway. Similarly the _`rename`_ and _`rename_all`_ will reflect to the generated OpenAPI doc.
223///
224/// * `rename_all = "..."` Supported at the container level.
225/// * `rename = "..."` Supported **only** at the field or variant level.
226/// * `skip = "..."` Supported **only** at the field or variant level.
227/// * `skip_serializing = "..."` Supported **only** at the field or variant level.
228/// * `skip_deserializing = "..."` Supported **only** at the field or variant level.
229/// * `skip_serializing_if = "..."` Supported **only** at the field level.
230/// * `with = ...` Supported **only at field level.**
231/// * `tag = "..."` Supported at the container level. `tag` attribute works as a [discriminator field][discriminator] for an enum.
232/// * `content = "..."` Supported at the container level, allows [adjacently-tagged enums](https://serde.rs/enum-representations.html#adjacently-tagged).
233/// This attribute requires that a `tag` is present, otherwise serde will trigger a compile-time
234/// failure.
235/// * `untagged` Supported at the container level. Allows [untagged
236/// enum representation](https://serde.rs/enum-representations.html#untagged).
237/// * `default` Supported at the container level and field level according to [serde attributes].
238/// * `flatten` Supported at the field level.
239///
240/// Other _`serde`_ attributes works as is but does not have any effect on the generated OpenAPI doc.
241///
242/// **Note!** `tag` attribute has some limitations like it cannot be used
243/// with **unnamed field structs** and **tuple types**. See more at
244/// [enum representation docs](https://serde.rs/enum-representations.html).
245///
246/// **Note!** `with` attribute is used in tandem with [serde_with](https://github.com/jonasbb/serde_with) to recognize
247/// _[`double_option`](https://docs.rs/serde_with/latest/serde_with/rust/double_option/index.html)_ from **field value**.
248/// _`double_option`_ is **only** supported attribute from _`serde_with`_ crate.
249///
250/// ```rust
251/// # use serde::Serialize;
252/// # use utoipa::ToSchema;
253/// #[derive(Serialize, ToSchema)]
254/// struct Foo(String);
255///
256/// #[derive(Serialize, ToSchema)]
257/// #[serde(rename_all = "camelCase")]
258/// enum Bar {
259/// UnitValue,
260/// #[serde(rename_all = "camelCase")]
261/// NamedFields {
262/// #[serde(rename = "id")]
263/// named_id: &'static str,
264/// name_list: Option<Vec<String>>
265/// },
266/// UnnamedFields(Foo),
267/// #[serde(skip)]
268/// SkipMe,
269/// }
270/// ```
271///
272/// _**Add custom `tag` to change JSON representation to be internally tagged.**_
273/// ```rust
274/// # use serde::Serialize;
275/// # use utoipa::ToSchema;
276/// #[derive(Serialize, ToSchema)]
277/// struct Foo(String);
278///
279/// #[derive(Serialize, ToSchema)]
280/// #[serde(tag = "tag")]
281/// enum Bar {
282/// UnitValue,
283/// NamedFields {
284/// id: &'static str,
285/// names: Option<Vec<String>>
286/// },
287/// }
288/// ```
289///
290/// _**Add serde `default` attribute for MyValue struct. Similarly `default` could be added to
291/// individual fields as well. If `default` is given the field's affected will be treated
292/// as optional.**_
293/// ```rust
294/// #[derive(utoipa::ToSchema, serde::Deserialize, Default)]
295/// #[serde(default)]
296/// struct MyValue {
297/// field: String
298/// }
299/// ```
300///
301/// # `#[repr(...)]` attribute support
302///
303/// [Serde repr](https://github.com/dtolnay/serde-repr) allows field-less enums be represented by
304/// their numeric value.
305///
306/// * `repr(u*)` for unsigned integer.
307/// * `repr(i*)` for signed integer.
308///
309/// **Supported schema attributes**
310///
311/// * `example = ...` Can be method reference or _`json!(...)`_.
312/// * `default = ...` Can be method reference or _`json!(...)`_.
313/// * `title = ...` Literal string value. Can be used to define title for enum in OpenAPI
314/// document. Some OpenAPI code generation libraries also use this field as a name for the
315/// enum. __Note!__ ___Complex enum (enum with other than unit variants) does not support title!___
316/// * `as = ...` Can be used to define alternative path and name for the schema what will be used in
317/// the OpenAPI. E.g _`as = path::to::Pet`_. This would make the schema appear in the generated
318/// OpenAPI spec as _`path.to.Pet`_.
319///
320/// _**Create enum with numeric values.**_
321/// ```rust
322/// # use utoipa::ToSchema;
323/// #[derive(ToSchema)]
324/// #[repr(u8)]
325/// #[schema(default = default_value, example = 2)]
326/// enum Mode {
327/// One = 1,
328/// Two,
329/// }
330///
331/// fn default_value() -> u8 {
332/// 1
333/// }
334/// ```
335///
336/// _**You can use `skip` and `tag` attributes from serde.**_
337/// ```rust
338/// # use utoipa::ToSchema;
339/// #[derive(ToSchema, serde::Serialize)]
340/// #[repr(i8)]
341/// #[serde(tag = "code")]
342/// enum ExitCode {
343/// Error = -1,
344/// #[serde(skip)]
345/// Unknown = 0,
346/// Ok = 1,
347/// }
348/// ```
349///
350/// # Generic schemas with aliases
351///
352/// Schemas can also be generic which allows reusing types. This enables certain behaviour patters
353/// where super type declares common code for type aliases.
354///
355/// In this example we have common `Status` type which accepts one generic type. It is then defined
356/// with `#[aliases(...)]` that it is going to be used with [`String`](std::string::String) and [`i32`] values.
357/// The generic argument could also be another [`ToSchema`][to_schema] as well.
358/// ```rust
359/// # use utoipa::{ToSchema, OpenApi};
360/// #[derive(ToSchema)]
361/// #[aliases(StatusMessage = Status<String>, StatusNumber = Status<i32>)]
362/// struct Status<T> {
363/// value: T
364/// }
365///
366/// #[derive(OpenApi)]
367/// #[openapi(
368/// components(schemas(StatusMessage, StatusNumber))
369/// )]
370/// struct ApiDoc;
371/// ```
372///
373/// The `#[aliases(...)]` is just syntactic sugar and will create Rust [type aliases](https://doc.rust-lang.org/reference/items/type-aliases.html)
374/// behind the scenes which then can be later referenced anywhere in code.
375///
376/// **Note!** You should never register generic type itself in `components(...)` so according above example `Status<...>` should not be registered
377/// because it will not render the type correctly and will cause an error in generated OpenAPI spec.
378///
379/// # Examples
380///
381/// _**Simple example of a Pet with descriptions and object level example.**_
382/// ```rust
383/// # use utoipa::ToSchema;
384/// /// This is a pet.
385/// #[derive(ToSchema)]
386/// #[schema(example = json!({"name": "bob the cat", "id": 0}))]
387/// struct Pet {
388/// /// Unique id of a pet.
389/// id: u64,
390/// /// Name of a pet.
391/// name: String,
392/// /// Age of a pet if known.
393/// age: Option<i32>,
394/// }
395/// ```
396///
397/// _**The `schema` attribute can also be placed at field level as follows.**_
398/// ```rust
399/// # use utoipa::ToSchema;
400/// #[derive(ToSchema)]
401/// struct Pet {
402/// #[schema(example = 1, default = 0)]
403/// id: u64,
404/// name: String,
405/// age: Option<i32>,
406/// }
407/// ```
408///
409/// _**You can also use method reference for attribute values.**_
410/// ```rust
411/// # use utoipa::ToSchema;
412/// #[derive(ToSchema)]
413/// struct Pet {
414/// #[schema(example = u64::default, default = u64::default)]
415/// id: u64,
416/// #[schema(default = default_name)]
417/// name: String,
418/// age: Option<i32>,
419/// }
420///
421/// fn default_name() -> String {
422/// "bob".to_string()
423/// }
424/// ```
425///
426/// _**For enums and unnamed field structs you can define `schema` at type level.**_
427/// ```rust
428/// # use utoipa::ToSchema;
429/// #[derive(ToSchema)]
430/// #[schema(example = "Bus")]
431/// enum VehicleType {
432/// Rocket, Car, Bus, Submarine
433/// }
434/// ```
435///
436/// _**Also you write complex enum combining all above types.**_
437/// ```rust
438/// # use utoipa::ToSchema;
439/// #[derive(ToSchema)]
440/// enum ErrorResponse {
441/// InvalidCredentials,
442/// #[schema(default = String::default, example = "Pet not found")]
443/// NotFound(String),
444/// System {
445/// #[schema(example = "Unknown system failure")]
446/// details: String,
447/// }
448/// }
449/// ```
450///
451/// _**It is possible to specify the title of each variant to help generators create named structures.**_
452/// ```rust
453/// # use utoipa::ToSchema;
454/// #[derive(ToSchema)]
455/// enum ErrorResponse {
456/// #[schema(title = "InvalidCredentials")]
457/// InvalidCredentials,
458/// #[schema(title = "NotFound")]
459/// NotFound(String),
460/// }
461/// ```
462///
463/// _**Use `xml` attribute to manipulate xml output.**_
464/// ```rust
465/// # use utoipa::ToSchema;
466/// #[derive(ToSchema)]
467/// #[schema(xml(name = "user", prefix = "u", namespace = "https://user.xml.schema.test"))]
468/// struct User {
469/// #[schema(xml(attribute, prefix = "u"))]
470/// id: i64,
471/// #[schema(xml(name = "user_name", prefix = "u"))]
472/// username: String,
473/// #[schema(xml(wrapped(name = "linkList"), name = "link"))]
474/// links: Vec<String>,
475/// #[schema(xml(wrapped, name = "photo_url"))]
476/// photos_urls: Vec<String>
477/// }
478/// ```
479///
480/// _**Use of Rust's own `#[deprecated]` attribute will reflect to generated OpenAPI spec.**_
481/// ```rust
482/// # use utoipa::ToSchema;
483/// #[derive(ToSchema)]
484/// #[deprecated]
485/// struct User {
486/// id: i64,
487/// username: String,
488/// links: Vec<String>,
489/// #[deprecated]
490/// photos_urls: Vec<String>
491/// }
492/// ```
493///
494/// _**Enforce type being used in OpenAPI spec to [`String`] with `value_type` and set format to octet stream
495/// with [`SchemaFormat::KnownFormat(KnownFormat::Binary)`][binary].**_
496/// ```rust
497/// # use utoipa::ToSchema;
498/// #[derive(ToSchema)]
499/// struct Post {
500/// id: i32,
501/// #[schema(value_type = String, format = Binary)]
502/// value: Vec<u8>,
503/// }
504/// ```
505///
506/// _**Enforce type being used in OpenAPI spec to [`String`] with `value_type` option.**_
507/// ```rust
508/// # use utoipa::ToSchema;
509/// #[derive(ToSchema)]
510/// #[schema(value_type = String)]
511/// struct Value(i64);
512/// ```
513///
514/// _**Override the `Bar` reference with a `custom::NewBar` reference.**_
515/// ```rust
516/// # use utoipa::ToSchema;
517/// # mod custom {
518/// # struct NewBar;
519/// # }
520/// #
521/// # struct Bar;
522/// #[derive(ToSchema)]
523/// struct Value {
524/// #[schema(value_type = custom::NewBar)]
525/// field: Bar,
526/// };
527/// ```
528///
529/// _**Use a virtual `Object` type to render generic `object` _(`type: object`)_ in OpenAPI spec.**_
530/// ```rust
531/// # use utoipa::ToSchema;
532/// # mod custom {
533/// # struct NewBar;
534/// # }
535/// #
536/// # struct Bar;
537/// #[derive(ToSchema)]
538/// struct Value {
539/// #[schema(value_type = Object)]
540/// field: Bar,
541/// };
542/// ```
543///
544/// _**Serde `rename` / `rename_all` will take precedence over schema `rename` / `rename_all`.**_
545/// ```rust
546/// #[derive(utoipa::ToSchema, serde::Deserialize)]
547/// #[serde(rename_all = "lowercase")]
548/// #[schema(rename_all = "UPPERCASE")]
549/// enum Random {
550/// #[serde(rename = "string_value")]
551/// #[schema(rename = "custom_value")]
552/// String(String),
553///
554/// Number {
555/// id: i32,
556/// }
557/// }
558/// ```
559///
560/// _**Add `title` to the enum.**_
561/// ```rust
562/// #[derive(utoipa::ToSchema)]
563/// #[schema(title = "UserType")]
564/// enum UserType {
565/// Admin,
566/// Moderator,
567/// User,
568/// }
569/// ```
570///
571/// _**Example with validation attributes.**_
572/// ```rust
573/// #[derive(utoipa::ToSchema)]
574/// struct Item {
575/// #[schema(maximum = 10, minimum = 5, multiple_of = 2.5)]
576/// id: i32,
577/// #[schema(max_length = 10, min_length = 5, pattern = "[a-z]*")]
578/// value: String,
579/// #[schema(max_items = 5, min_items = 1)]
580/// items: Vec<String>,
581/// }
582/// ````
583///
584/// _**Use `schema_with` to manually implement schema for a field.**_
585/// ```rust
586/// # use utoipa::openapi::schema::{Object, ObjectBuilder};
587/// fn custom_type() -> Object {
588/// ObjectBuilder::new()
589/// .schema_type(utoipa::openapi::SchemaType::String)
590/// .format(Some(utoipa::openapi::SchemaFormat::Custom(
591/// "email".to_string(),
592/// )))
593/// .description(Some("this is the description"))
594/// .build()
595/// }
596///
597/// #[derive(utoipa::ToSchema)]
598/// struct Value {
599/// #[schema(schema_with = custom_type)]
600/// id: String,
601/// }
602/// ```
603///
604/// _**Use `as` attribute to change the name and the path of the schema in the generated OpenAPI
605/// spec.**_
606/// ```rust
607/// #[derive(utoipa::ToSchema)]
608/// #[schema(as = api::models::person::Person)]
609/// struct Person {
610/// name: String,
611/// }
612/// ```
613///
614/// More examples for _`value_type`_ in [`IntoParams` derive docs][into_params].
615///
616/// [to_schema]: trait.ToSchema.html
617/// [known_format]: openapi/schema/enum.KnownFormat.html
618/// [binary]: openapi/schema/enum.KnownFormat.html#variant.Binary
619/// [xml]: openapi/xml/struct.Xml.html
620/// [into_params]: derive.IntoParams.html
621/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
622/// [serde attributes]: https://serde.rs/attributes.html
623/// [discriminator]: openapi/schema/struct.Discriminator.html
624/// [enum_schema]: derive.ToSchema.html#enum-optional-configuration-options-for-schema
625/// [openapi_derive]: derive.OpenApi.html
626/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
627pub fn derive_to_schema(input: TokenStream) -> TokenStream {
628 let DeriveInput {
629 attrs,
630 ident,
631 data,
632 generics,
633 vis,
634 } = syn::parse_macro_input!(input);
635
636 let schema = Schema::new(&data, &attrs, &ident, &generics, &vis);
637
638 schema.to_token_stream().into()
639}
640
641#[proc_macro_error]
642#[proc_macro_attribute]
643/// Path attribute macro implements OpenAPI path for the decorated function.
644///
645/// This is a `#[derive]` implementation for [`Path`][path] trait. Macro accepts set of attributes that can
646/// be used to configure and override default values what are resolved automatically.
647///
648/// You can use the Rust's own `#[deprecated]` attribute on functions to mark it as deprecated and it will
649/// reflect to the generated OpenAPI spec. Only **parameters** has a special **deprecated** attribute to define them as deprecated.
650///
651/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version but this is is not supported in
652/// OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
653/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
654///
655/// Doc comment at decorated function will be used for _`description`_ and _`summary`_ of the path.
656/// First line of the doc comment will be used as the _`summary`_ and the whole doc comment will be
657/// used as _`description`_.
658/// ```rust
659/// /// This is a summary of the operation
660/// ///
661/// /// All lines of the doc comment will be included to operation description.
662/// #[utoipa::path(get, path = "/operation")]
663/// fn operation() {}
664/// ```
665///
666/// # Path Attributes
667///
668/// * `operation` _**Must be first parameter!**_ Accepted values are known http operations such as
669/// _`get, post, put, delete, head, options, connect, patch, trace`_.
670///
671/// * `path = "..."` Must be OpenAPI format compatible str with arguments within curly braces. E.g _`{id}`_
672///
673/// * `operation_id = ...` Unique operation id for the endpoint. By default this is mapped to function name.
674/// The operation_id can be any valid expression (e.g. string literals, macro invocations, variables) so long
675/// as its result can be converted to a `String` using `String::from`.
676///
677/// * `context_path = "..."` Can add optional scope for **path**. The **context_path** will be prepended to beginning of **path**.
678/// This is particularly useful when **path** does not contain the full path to the endpoint. For example if web framework
679/// allows operation to be defined under some context path or scope which does not reflect to the resolved path then this
680/// **context_path** can become handy to alter the path.
681///
682/// * `tag = "..."` Can be used to group operations. Operations with same tag are grouped together. By default
683/// this is derived from the handler that is given to [`OpenApi`][openapi]. If derive results empty str
684/// then default value _`crate`_ is used instead.
685///
686/// * `request_body = ... | request_body(...)` Defining request body indicates that the request is expecting request body within
687/// the performed request.
688///
689/// * `responses(...)` Slice of responses the endpoint is going to possibly return to the caller.
690///
691/// * `params(...)` Slice of params that the endpoint accepts.
692///
693/// * `security(...)` List of [`SecurityRequirement`][security]s local to the path operation.
694///
695/// # Request Body Attributes
696///
697/// **Simple format definition by `request_body = ...`**
698/// * _`request_body = Type`_, _`request_body = inline(Type)`_ or _`request_body = ref("...")`_.
699/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
700/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
701/// [`ToSchema`][to_schema] types. _`ref("./external.json")`_ can be used to reference external
702/// json file for body schema. **Note!** Utoipa does **not** guarantee that free form _`ref`_ is accessbile via
703/// OpenAPI doc or Swagger UI, users are eligible to make these guarantees.
704///
705/// **Advanced format definition by `request_body(...)`**
706/// * `content = ...` Can be _`content = Type`_, _`content = inline(Type)`_ or _`content = ref("...")`_. The
707/// given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec
708/// or Map etc. With _`inline(...)`_ the schema will be inlined instead of a referenced
709/// which is the default for [`ToSchema`][to_schema] types. _`ref("./external.json")`_
710/// can be used to reference external json file for body schema. **Note!** Utoipa does **not** guarantee
711/// that free form _`ref`_ is accessible via OpenAPI doc or Swagger UI, users are eligible
712/// to make these guarantees.
713///
714/// * `description = "..."` Define the description for the request body object as str.
715///
716/// * `content_type = "..."` Can be used to override the default behavior of auto resolving the content type
717/// from the `content` attribute. If defined the value should be valid content type such as
718/// _`application/json`_. By default the content type is _`text/plain`_ for
719/// [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and
720/// _`application/json`_ for struct and complex enum types.
721///
722/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
723/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
724///
725/// * `examples(...)` Define multiple examples for single request body. This attribute is mutually
726/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
727/// This has same syntax as _`examples(...)`_ in [Response Attributes](#response-attributes)
728/// _examples(...)_
729///
730/// _**Example request body definitions.**_
731/// ```text
732/// request_body(content = String, description = "Xml as string request", content_type = "text/xml"),
733/// request_body = Pet,
734/// request_body = Option<[Pet]>,
735/// ```
736///
737/// # Response Attributes
738///
739/// * `status = ...` Is either a valid http status code integer. E.g. _`200`_ or a string value representing
740/// a range such as _`"4XX"`_ or `"default"` or a valid _`http::status::StatusCode`_.
741/// _`StatusCode`_ can either be use path to the status code or _status code_ constant directly.
742///
743/// * `description = "..."` Define description for the response as str.
744///
745/// * `body = ...` Optional response body object type. When left empty response does not expect to send any
746/// response body. Can be _`body = Type`_, _`body = inline(Type)`_, or _`body = ref("...")`_.
747/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
748/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
749/// [`ToSchema`][to_schema] types. _`ref("./external.json")`_
750/// can be used to reference external json file for body schema. **Note!** Utoipa does **not** guarantee
751/// that free form _`ref`_ is accessible via OpenAPI doc or Swagger UI, users are eligible
752/// to make these guarantees.
753///
754/// * `content_type = "..." | content_type = [...]` Can be used to override the default behavior of auto resolving the content type
755/// from the `body` attribute. If defined the value should be valid content type such as
756/// _`application/json`_. By default the content type is _`text/plain`_ for
757/// [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and
758/// _`application/json`_ for struct and complex enum types.
759/// Content type can also be slice of **content_type** values if the endpoint support returning multiple
760/// response content types. E.g _`["application/json", "text/xml"]`_ would indicate that endpoint can return both
761/// _`json`_ and _`xml`_ formats. **The order** of the content types define the default example show first in
762/// the Swagger UI. Swagger UI wil use the first _`content_type`_ value as a default example.
763///
764/// * `headers(...)` Slice of response headers that are returned back to a caller.
765///
766/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
767/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
768///
769/// * `response = ...` Type what implements [`ToResponse`][to_response_trait] trait. This can alternatively be used to
770/// define response attributes. _`response`_ attribute cannot co-exist with other than _`status`_ attribute.
771///
772/// * `content((...), (...))` Can be used to define multiple return types for single response status. Supported format for single
773/// _content_ is `(content_type = response_body, example = "...", examples(...))`. _`example`_
774/// and _`examples`_ are optional arguments. Examples attribute behaves exactly same way as in
775/// the response and is mutually exclusive with the example attribute.
776///
777/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
778/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
779/// * `name = ...` This is first attribute and value must be literal string.
780/// * `summary = ...` Short description of example. Value must be literal string.
781/// * `description = ...` Long description of example. Attribute supports markdown for rich text
782/// representation. Value must be literal string.
783/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
784/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
785/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
786/// the _`value`_ attribute. Value must be literal string.
787///
788/// _**Example of example definition.**_
789/// ```text
790/// ("John" = (summary = "This is John", value = json!({"name": "John"})))
791/// ```
792///
793/// **Minimal response format:**
794/// ```text
795/// responses(
796/// (status = 200, description = "success response"),
797/// (status = 404, description = "resource missing"),
798/// (status = "5XX", description = "server error"),
799/// (status = StatusCode::INTERNAL_SERVER_ERROR, description = "internal server error"),
800/// (status = IM_A_TEAPOT, description = "happy easter")
801/// )
802/// ```
803///
804/// **More complete Response:**
805/// ```text
806/// responses(
807/// (status = 200, description = "Success response", body = Pet, content_type = "application/json",
808/// headers(...),
809/// example = json!({"id": 1, "name": "bob the cat"})
810/// )
811/// )
812/// ```
813///
814/// **Response with multiple response content types:**
815/// ```text
816/// responses(
817/// (status = 200, description = "Success response", body = Pet, content_type = ["application/json", "text/xml"])
818/// )
819/// ```
820///
821/// **Multiple response return types with _`content(...)`_ attribute:**
822///
823/// _**Define multiple response return types for single response status with their own example.**_
824/// ```text
825/// responses(
826/// (status = 200, content(
827/// ("application/vnd.user.v1+json" = User, example = json!(User {id: "id".to_string()})),
828/// ("application/vnd.user.v2+json" = User2, example = json!(User2 {id: 2}))
829/// )
830/// )
831/// )
832/// ```
833///
834/// ### Using `ToResponse` for reusable responses
835///
836/// _**`ReusableResponse` must be a type that implements [`ToResponse`][to_response_trait].**_
837/// ```text
838/// responses(
839/// (status = 200, response = ReusableResponse)
840/// )
841/// ```
842///
843/// _**[`ToResponse`][to_response_trait] can also be inlined to the responses map.**_
844/// ```text
845/// responses(
846/// (status = 200, response = inline(ReusableResponse))
847/// )
848/// ```
849///
850/// ## Responses from `IntoResponses`
851///
852/// _**Responses for a path can be specified with one or more types that implement
853/// [`IntoResponses`][into_responses_trait].**_
854/// ```text
855/// responses(MyResponse)
856/// ```
857///
858/// # Response Header Attributes
859///
860/// * `name` Name of the header. E.g. _`x-csrf-token`_
861///
862/// * `type` Additional type of the header value. Can be `Type` or `inline(Type)`.
863/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
864/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
865/// [`ToSchema`][to_schema] types. **Reminder!** It's up to the user to use valid type for the
866/// response header.
867///
868/// * `description = "..."` Can be used to define optional description for the response header as str.
869///
870/// **Header supported formats:**
871///
872/// ```text
873/// ("x-csrf-token"),
874/// ("x-csrf-token" = String, description = "New csrf token"),
875/// ```
876///
877/// # Params Attributes
878///
879/// The list of attributes inside the `params(...)` attribute can take two forms: [Tuples](#tuples) or [IntoParams
880/// Type](#intoparams-type).
881///
882/// ## Tuples
883///
884/// In the tuples format, parameters are specified using the following attributes inside a list of
885/// tuples separated by commas:
886///
887/// * `name` _**Must be the first argument**_. Define the name for parameter.
888///
889/// * `parameter_type` Define possible type for the parameter. Can be `Type` or `inline(Type)`.
890/// The given _`Type`_ can be any Rust type that is JSON parseable. It can be Option, Vec or Map etc.
891/// With _`inline(...)`_ the schema will be inlined instead of a referenced which is the default for
892/// [`ToSchema`][to_schema] types. Parameter type is placed after `name` with
893/// equals sign E.g. _`"id" = String`_
894///
895/// * `in` _**Must be placed after name or parameter_type**_. Define the place of the parameter.
896/// This must be one of the variants of [`openapi::path::ParameterIn`][in_enum].
897/// E.g. _`Path, Query, Header, Cookie`_
898///
899/// * `deprecated` Define whether the parameter is deprecated or not. Can optionally be defined
900/// with explicit `bool` value as _`deprecated = bool`_.
901///
902/// * `description = "..."` Define possible description for the parameter as str.
903///
904/// * `style = ...` Defines how parameters are serialized by [`ParameterStyle`][style]. Default values are based on _`in`_ attribute.
905///
906/// * `explode` Defines whether new _`parameter=value`_ is created for each parameter within _`object`_ or _`array`_.
907///
908/// * `allow_reserved` Defines whether reserved characters _`:/?#[]@!$&'()*+,;=`_ is allowed within value.
909///
910/// * `example = ...` Can method reference or _`json!(...)`_. Given example
911/// will override any example in underlying parameter type.
912///
913/// ##### Parameter type attributes
914///
915/// These attributes supported when _`parameter_type`_ is present. Either by manually providing one
916/// or otherwise resolved e.g from path macro argument when _`actix_extras`_ crate feature is
917/// enabled.
918///
919/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
920/// an open value as a string. By default the format is derived from the type of the property
921/// according OpenApi spec.
922///
923/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
924///
925/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
926///
927/// * `xml(...)` Can be used to define [`Xml`][xml] object properties for the parameter type.
928/// See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
929///
930/// * `nullable` Defines property is nullable (note this is different to non-required).
931///
932/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
933/// division will result an `integer`. Value must be strictly above _`0`_.
934///
935/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
936///
937/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
938///
939/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
940///
941/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
942///
943/// * `max_length = ...` Can be used to define maximum length for `string` types.
944///
945/// * `min_length = ...` Can be used to define minimum length for `string` types.
946///
947/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
948///
949/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
950/// be non-negative integer.
951///
952/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
953/// be non-negative integer.
954///
955/// **For example:**
956///
957/// ```text
958/// params(
959/// ("id" = String, Path, deprecated, description = "Pet database id"),
960/// ("name", Path, deprecated, description = "Pet name"),
961/// (
962/// "value" = inline(Option<[String]>),
963/// Query,
964/// description = "Value description",
965/// style = Form,
966/// allow_reserved,
967/// deprecated,
968/// explode,
969/// example = json!(["Value"])),
970/// max_length = 10,
971/// min_items = 1
972/// )
973/// )
974/// ```
975///
976/// ## IntoParams Type
977///
978/// In the IntoParams parameters format, the parameters are specified using an identifier for a type
979/// that implements [`IntoParams`][into_params]. See [`IntoParams`][into_params] for an
980/// example.
981///
982/// ```text
983/// params(MyParameters)
984/// ```
985///
986/// **Note!** that `MyParameters` can also be used in combination with the [tuples
987/// representation](#tuples) or other structs.
988/// ```text
989/// params(
990/// MyParameters1,
991/// MyParameters2,
992/// ("id" = String, Path, deprecated, description = "Pet database id"),
993/// )
994/// ```
995///
996/// # Security Requirement Attributes
997///
998/// * `name` Define the name for security requirement. This must match to name of existing
999/// [`SecuritySchema`][security_schema].
1000/// * `scopes = [...]` Define the list of scopes needed. These must be scopes defined already in
1001/// existing [`SecuritySchema`][security_schema].
1002///
1003/// **Security Requirement supported formats:**
1004///
1005/// ```text
1006/// (),
1007/// ("name" = []),
1008/// ("name" = ["scope1", "scope2"]),
1009/// ```
1010///
1011/// Leaving empty _`()`_ creates an empty [`SecurityRequirement`][security] this is useful when
1012/// security requirement is optional for operation.
1013///
1014/// # actix_extras feature support for actix-web
1015///
1016/// **actix_extras** feature gives **utoipa** ability to parse path operation information from **actix-web** types and macros.
1017///
1018/// 1. Ability to parse `path` from **actix-web** path attribute macros e.g. _`#[get(...)]`_.
1019/// 2. Ability to parse [`std::primitive`] or [`String`] or [`tuple`] typed `path` parameters from **actix-web** _`web::Path<...>`_.
1020/// 3. Ability to parse `path` and `query` parameters form **actix-web** _`web::Path<...>`_, _`web::Query<...>`_ types
1021/// with [`IntoParams`][into_params] trait.
1022///
1023/// See the **actix_extras** in action in examples [todo-actix](https://github.com/juhaku/utoipa/tree/master/examples/todo-actix).
1024///
1025/// With **actix_extras** feature enabled the you can leave out definitions for **path**, **operation**
1026/// and **parameter types**.
1027/// ```rust
1028/// use actix_web::{get, web, HttpResponse, Responder};
1029/// use serde_json::json;
1030///
1031/// /// Get Pet by id
1032/// #[utoipa::path(
1033/// responses(
1034/// (status = 200, description = "Pet found from database")
1035/// ),
1036/// params(
1037/// ("id", description = "Pet id"),
1038/// )
1039/// )]
1040/// #[get("/pet/{id}")]
1041/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1042/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1043/// }
1044/// ```
1045///
1046/// With **actix_extras** you may also not to list any _**params**_ if you do not want to specify any description for them. Params are
1047/// resolved from path and the argument types of handler
1048/// ```rust
1049/// use actix_web::{get, web, HttpResponse, Responder};
1050/// use serde_json::json;
1051///
1052/// /// Get Pet by id
1053/// #[utoipa::path(
1054/// responses(
1055/// (status = 200, description = "Pet found from database")
1056/// )
1057/// )]
1058/// #[get("/pet/{id}")]
1059/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1060/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1061/// }
1062/// ```
1063///
1064/// # rocket_extras feature support for rocket
1065///
1066/// **rocket_extras** feature enhances path operation parameter support. It gives **utoipa** ability to parse `path`, `path parameters`
1067/// and `query parameters` based on arguments given to **rocket** proc macros such as _**`#[get(...)]`**_.
1068///
1069/// 1. It is able to parse parameter types for [primitive types][primitive], [`String`], [`Vec`], [`Option`] or [`std::path::PathBuf`]
1070/// type.
1071/// 2. It is able to determine `parameter_in` for [`IntoParams`][into_params] trait used for `FromForm` type of query parameters.
1072///
1073/// See the **rocket_extras** in action in examples [rocket-todo](https://github.com/juhaku/utoipa/tree/master/examples/rocket-todo).
1074///
1075///
1076/// # axum_extras feature support for axum
1077///
1078/// **axum_extras** feature enhances parameter support for path operation in following ways.
1079///
1080/// 1. It allows users to use tuple style path parameters e.g. _`Path((id, name)): Path<(i32, String)>`_ and resolves
1081/// parameter names and types from it.
1082/// 2. It enhances [`IntoParams` derive][into_params_derive] functionality by automatically resolving _`parameter_in`_ from
1083/// _`Path<...>`_ or _`Query<...>`_ handler function arguments.
1084///
1085/// _**Resole path argument types from tuple style handler arguments.**_
1086/// ```rust
1087/// # use axum::extract::Path;
1088/// /// Get todo by id and name.
1089/// #[utoipa::path(
1090/// get,
1091/// path = "/todo/{id}",
1092/// params(
1093/// ("id", description = "Todo id"),
1094/// ("name", description = "Todo name")
1095/// ),
1096/// responses(
1097/// (status = 200, description = "Get todo success", body = String)
1098/// )
1099/// )]
1100/// async fn get_todo(
1101/// Path((id, name)): Path<(i32, String)>
1102/// ) -> String {
1103/// String::new()
1104/// }
1105/// ```
1106///
1107/// _**Use `IntoParams` to resolve query parameters.**_
1108/// ```rust
1109/// # use serde::Deserialize;
1110/// # use utoipa::IntoParams;
1111/// # use axum::{extract::Query, Json};
1112/// #[derive(Deserialize, IntoParams)]
1113/// struct TodoSearchQuery {
1114/// /// Search by value. Search is incase sensitive.
1115/// value: String,
1116/// /// Search by `done` status.
1117/// done: bool,
1118/// }
1119///
1120/// /// Search Todos by query params.
1121/// #[utoipa::path(
1122/// get,
1123/// path = "/todo/search",
1124/// params(
1125/// TodoSearchQuery
1126/// ),
1127/// responses(
1128/// (status = 200, description = "List matching todos by query", body = [String])
1129/// )
1130/// )]
1131/// async fn search_todos(
1132/// query: Query<TodoSearchQuery>,
1133/// ) -> Json<Vec<String>> {
1134/// Json(vec![])
1135/// }
1136/// ```
1137///
1138/// # Examples
1139///
1140/// _**More complete example.**_
1141/// ```rust
1142/// # struct Pet {
1143/// # id: u64,
1144/// # name: String,
1145/// # }
1146/// #
1147/// #[utoipa::path(
1148/// post,
1149/// operation_id = "custom_post_pet",
1150/// path = "/pet",
1151/// tag = "pet_handlers",
1152/// request_body(content = Pet, description = "Pet to store the database", content_type = "application/json"),
1153/// responses(
1154/// (status = 200, description = "Pet stored successfully", body = Pet, content_type = "application/json",
1155/// headers(
1156/// ("x-cache-len" = String, description = "Cache length")
1157/// ),
1158/// example = json!({"id": 1, "name": "bob the cat"})
1159/// ),
1160/// ),
1161/// params(
1162/// ("x-csrf-token" = String, Header, deprecated, description = "Current csrf token of user"),
1163/// ),
1164/// security(
1165/// (),
1166/// ("my_auth" = ["read:items", "edit:items"]),
1167/// ("token_jwt" = [])
1168/// )
1169/// )]
1170/// fn post_pet(pet: Pet) -> Pet {
1171/// Pet {
1172/// id: 4,
1173/// name: "bob the cat".to_string(),
1174/// }
1175/// }
1176/// ```
1177///
1178/// _**More minimal example with the defaults.**_
1179/// ```rust
1180/// # struct Pet {
1181/// # id: u64,
1182/// # name: String,
1183/// # }
1184/// #
1185/// #[utoipa::path(
1186/// post,
1187/// path = "/pet",
1188/// request_body = Pet,
1189/// responses(
1190/// (status = 200, description = "Pet stored successfully", body = Pet,
1191/// headers(
1192/// ("x-cache-len", description = "Cache length")
1193/// )
1194/// ),
1195/// ),
1196/// params(
1197/// ("x-csrf-token", Header, description = "Current csrf token of user"),
1198/// )
1199/// )]
1200/// fn post_pet(pet: Pet) -> Pet {
1201/// Pet {
1202/// id: 4,
1203/// name: "bob the cat".to_string(),
1204/// }
1205/// }
1206/// ```
1207///
1208/// _**Use of Rust's own `#[deprecated]` attribute will reflect to the generated OpenAPI spec and mark this operation as deprecated.**_
1209/// ```rust
1210/// # use actix_web::{get, web, HttpResponse, Responder};
1211/// # use serde_json::json;
1212/// #[utoipa::path(
1213/// responses(
1214/// (status = 200, description = "Pet found from database")
1215/// ),
1216/// params(
1217/// ("id", description = "Pet id"),
1218/// )
1219/// )]
1220/// #[get("/pet/{id}")]
1221/// #[deprecated]
1222/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1223/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1224/// }
1225/// ```
1226///
1227/// _**Define context path for endpoint. The resolved **path** shown in OpenAPI doc will be `/api/pet/{id}`.**_
1228/// ```rust
1229/// # use actix_web::{get, web, HttpResponse, Responder};
1230/// # use serde_json::json;
1231/// #[utoipa::path(
1232/// context_path = "/api",
1233/// responses(
1234/// (status = 200, description = "Pet found from database")
1235/// )
1236/// )]
1237/// #[get("/pet/{id}")]
1238/// async fn get_pet_by_id(id: web::Path<i32>) -> impl Responder {
1239/// HttpResponse::Ok().json(json!({ "pet": format!("{:?}", &id.into_inner()) }))
1240/// }
1241/// ```
1242///
1243/// _**Example with multiple return types**_
1244/// ```rust
1245/// # trait User {}
1246/// # struct User1 {
1247/// # id: String
1248/// # }
1249/// # impl User for User1 {}
1250/// #[utoipa::path(
1251/// get,
1252/// path = "/user",
1253/// responses(
1254/// (status = 200, content(
1255/// ("application/vnd.user.v1+json" = User1, example = json!({"id": "id".to_string()})),
1256/// ("application/vnd.user.v2+json" = User2, example = json!({"id": 2}))
1257/// )
1258/// )
1259/// )
1260/// )]
1261/// fn get_user() -> Box<dyn User> {
1262/// Box::new(User1 {id: "id".to_string()})
1263/// }
1264/// ````
1265///
1266/// _**Example with multiple examples on single response.**_
1267///```rust
1268/// # #[derive(serde::Serialize, serde::Deserialize)]
1269/// # struct User {
1270/// # name: String
1271/// # }
1272/// #[utoipa::path(
1273/// get,
1274/// path = "/user",
1275/// responses(
1276/// (status = 200, body = User,
1277/// examples(
1278/// ("Demo" = (summary = "This is summary", description = "Long description",
1279/// value = json!(User{name: "Demo".to_string()}))),
1280/// ("John" = (summary = "Another user", value = json!({"name": "John"})))
1281/// )
1282/// )
1283/// )
1284/// )]
1285/// fn get_user() -> User {
1286/// User {name: "John".to_string()}
1287/// }
1288///```
1289///
1290/// [in_enum]: openapi/path/enum.ParameterIn.html
1291/// [path]: trait.Path.html
1292/// [to_schema]: trait.ToSchema.html
1293/// [openapi]: derive.OpenApi.html
1294/// [security]: openapi/security/struct.SecurityRequirement.html
1295/// [security_schema]: openapi/security/enum.SecurityScheme.html
1296/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
1297/// [into_params]: trait.IntoParams.html
1298/// [style]: openapi/path/enum.ParameterStyle.html
1299/// [into_responses_trait]: trait.IntoResponses.html
1300/// [into_params_derive]: derive.IntoParams.html
1301/// [to_response_trait]: trait.ToResponse.html
1302/// [known_format]: openapi/schema/enum.KnownFormat.html
1303/// [xml]: openapi/xml/struct.Xml.html
1304/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
1305pub fn path(attr: TokenStream, item: TokenStream) -> TokenStream {
1306 let path_attribute = syn::parse_macro_input!(attr as PathAttr);
1307
1308 #[cfg(any(
1309 feature = "actix_extras",
1310 feature = "rocket_extras",
1311 feature = "axum_extras",
1312 feature = "auto_into_responses"
1313 ))]
1314 let mut path_attribute = path_attribute;
1315
1316 let ast_fn = syn::parse::<ItemFn>(item).unwrap_or_abort();
1317 let fn_name = &*ast_fn.sig.ident.to_string();
1318
1319 #[cfg(feature = "auto_into_responses")]
1320 {
1321 if let Some(responses) = ext::auto_types::parse_fn_operation_responses(&ast_fn) {
1322 path_attribute.responses_from_into_responses(responses);
1323 };
1324 }
1325
1326 let mut resolved_operation = PathOperations::resolve_operation(&ast_fn);
1327 let resolved_path = PathOperations::resolve_path(
1328 &resolved_operation
1329 .as_mut()
1330 .map(|operation| mem::take(&mut operation.path))
1331 .or_else(|| path_attribute.path.as_ref().map(String::to_string)), // cannot use mem take because we need this later
1332 );
1333
1334 #[cfg(any(
1335 feature = "actix_extras",
1336 feature = "rocket_extras",
1337 feature = "axum_extras"
1338 ))]
1339 let mut resolved_path = resolved_path;
1340
1341 #[cfg(any(
1342 feature = "actix_extras",
1343 feature = "rocket_extras",
1344 feature = "axum_extras"
1345 ))]
1346 {
1347 use ext::ArgumentResolver;
1348 use path::parameter::Parameter;
1349 let args = resolved_path.as_mut().map(|path| mem::take(&mut path.args));
1350 let body = resolved_operation
1351 .as_mut()
1352 .map(|path| mem::take(&mut path.body))
1353 .unwrap_or_default();
1354
1355 let (arguments, into_params_types, body) =
1356 PathOperations::resolve_arguments(&ast_fn.sig.inputs, args, body);
1357
1358 let parameters = arguments
1359 .into_iter()
1360 .flatten()
1361 .map(Parameter::from)
1362 .chain(into_params_types.into_iter().flatten().map(Parameter::from));
1363 path_attribute.update_parameters_ext(parameters);
1364
1365 path_attribute.update_request_body(body);
1366 }
1367
1368 let path = Path::new(path_attribute, fn_name)
1369 .path_operation(resolved_operation.map(|operation| operation.path_operation))
1370 .path(|| resolved_path.map(|path| path.path))
1371 .doc_comments(CommentAttributes::from_attributes(&ast_fn.attrs).0)
1372 .deprecated(ast_fn.attrs.iter().find_map(|attr| {
1373
1374 if !matches!(attr.path().get_ident(), Some(ident) if &*ident.to_string() == "deprecated")
1375 {
1376 None
1377 } else {
1378 Some(true)
1379 }
1380 }));
1381
1382 quote! {
1383 #path
1384 #ast_fn
1385 }
1386 .into()
1387}
1388
1389#[proc_macro_error]
1390#[proc_macro_derive(OpenApi, attributes(openapi))]
1391/// Generate OpenApi base object with defaults from
1392/// project settings.
1393///
1394/// This is `#[derive]` implementation for [`OpenApi`][openapi] trait. The macro accepts one `openapi` argument.
1395///
1396/// # OpenApi `#[openapi(...)]` attributes
1397///
1398/// * `paths(...)` List of method references having attribute [`#[utoipa::path]`][path] macro.
1399/// * `components(schemas(...), responses(...))` Takes available _`component`_ configurations. Currently only
1400/// _`schema`_ and _`response`_ components are supported.
1401/// * `schemas(...)` List of [`ToSchema`][to_schema]s in OpenAPI schema.
1402/// * `responses(...)` List of types that implement
1403/// [`ToResponse`][to_response_trait].
1404/// * `modifiers(...)` List of items implementing [`Modify`][modify] trait for runtime OpenApi modification.
1405/// See the [trait documentation][modify] for more details.
1406/// * `security(...)` List of [`SecurityRequirement`][security]s global to all operations.
1407/// See more details in [`#[utoipa::path(...)]`][path] [attribute macro security options][path_security].
1408/// * `tags(...)` List of [`Tag`][tags] which must match the tag _**path operation**_. By default
1409/// the tag is derived from path given to **handlers** list or if undefined then `crate` is used by default.
1410/// Alternatively the tag name can be given to path operation via [`#[utoipa::path(...)]`][path] macro.
1411/// Tag can be used to define extra information for the api to produce richer documentation.
1412/// * `external_docs(...)` Can be used to reference external resource to the OpenAPI doc for extended documentation.
1413/// External docs can be in [`OpenApi`][openapi_struct] or in [`Tag`][tags] level.
1414/// * `servers(...)` Define [`servers`][servers] as derive argument to the _`OpenApi`_. Servers
1415/// are completely optional and thus can be omitted from the declaration.
1416/// * `info(...)` Declare [`Info`][info] attribute values used to override the default values
1417/// generated from Cargo environment variables. **Note!** Defined attributes will override the
1418/// whole attribute from generated values of Cargo environment variables. E.g. defining
1419/// `contact(name = ...)` will ultimately override whole contact of info and not just partially
1420/// the name.
1421///
1422/// OpenApi derive macro will also derive [`Info`][info] for OpenApi specification using Cargo
1423/// environment variables.
1424///
1425/// * env `CARGO_PKG_NAME` map to info `title`
1426/// * env `CARGO_PKG_VERSION` map to info `version`
1427/// * env `CARGO_PKG_DESCRIPTION` map info `description`
1428/// * env `CARGO_PKG_AUTHORS` map to contact `name` and `email` **only first author will be used**
1429/// * env `CARGO_PKG_LICENSE` map to info `license`
1430///
1431/// # `info(...)` attribute syntax
1432///
1433/// * `title = ...` Define title of the API. It can be literal string.
1434/// * `description = ...` Define description of the API. Markdown can be used for rich text
1435/// representation. It can be literal string or [`include_str!`] statement.
1436/// * `version = ...` Override default version from _`Cargo.toml`_. Value must be literal string.
1437/// * `contact(...)` Used to override the whole contact generated from environment variables.
1438/// * `name = ...` Define identifying name of contact person / organization. It Can be a literal string.
1439/// * `email = ...` Define email address of the contact person / organization. It can be a literal string.
1440/// * `url = ...` Define URL pointing to the contact information. It must be in URL formatted string.
1441/// * `license(...)` Used to override the whole license generated from environment variables.
1442/// * `name = ...` License name of the API. It can be a literal string.
1443/// * `url = ...` Define optional URL of the license. It must be URL formatted string.
1444///
1445/// # `servers(...)` attribute syntax
1446///
1447/// * `url = ...` Define the url for server. It can be literal string.
1448/// * `description = ...` Define description for the server. It can be literal string.
1449/// * `variables(...)` Can be used to define variables for the url.
1450/// * `name = ...` Is the first argument within parentheses. It must be literal string.
1451/// * `default = ...` Defines a default value for the variable if nothing else will be
1452/// provided. If _`enum_values`_ is defined the _`default`_ must be found within the enum
1453/// options. It can be a literal string.
1454/// * `description = ...` Define the description for the variable. It can be a literal string.
1455/// * `enum_values(...)` Define list of possible values for the variable. Values must be
1456/// literal strings.
1457///
1458/// _**Example server variable definition.**_
1459/// ```text
1460/// ("username" = (default = "demo", description = "Default username for API")),
1461/// ("port" = (enum_values("8080", "5000", "4545")))
1462/// ```
1463///
1464/// # Examples
1465///
1466/// _**Define OpenApi schema with some paths and components.**_
1467/// ```rust
1468/// # use utoipa::{OpenApi, ToSchema};
1469/// #
1470/// #[derive(ToSchema)]
1471/// struct Pet {
1472/// name: String,
1473/// age: i32,
1474/// }
1475///
1476/// #[derive(ToSchema)]
1477/// enum Status {
1478/// Active, InActive, Locked,
1479/// }
1480///
1481/// #[utoipa::path(get, path = "/pet")]
1482/// fn get_pet() -> Pet {
1483/// Pet {
1484/// name: "bob".to_string(),
1485/// age: 8,
1486/// }
1487/// }
1488///
1489/// #[utoipa::path(get, path = "/status")]
1490/// fn get_status() -> Status {
1491/// Status::Active
1492/// }
1493///
1494/// #[derive(OpenApi)]
1495/// #[openapi(
1496/// paths(get_pet, get_status),
1497/// components(schemas(Pet, Status)),
1498/// security(
1499/// (),
1500/// ("my_auth" = ["read:items", "edit:items"]),
1501/// ("token_jwt" = [])
1502/// ),
1503/// tags(
1504/// (name = "pets::api", description = "All about pets",
1505/// external_docs(url = "http://more.about.pets.api", description = "Find out more"))
1506/// ),
1507/// external_docs(url = "http://more.about.our.apis", description = "More about our APIs")
1508/// )]
1509/// struct ApiDoc;
1510/// ```
1511///
1512/// _**Define servers to OpenApi.**_
1513///```rust
1514/// # use utoipa::OpenApi;
1515/// #[derive(OpenApi)]
1516/// #[openapi(
1517/// servers(
1518/// (url = "http://localhost:8989", description = "Local server"),
1519/// (url = "http://api.{username}:{port}", description = "Remote API",
1520/// variables(
1521/// ("username" = (default = "demo", description = "Default username for API")),
1522/// ("port" = (default = "8080", enum_values("8080", "5000", "3030"), description = "Supported ports for API"))
1523/// )
1524/// )
1525/// )
1526/// )]
1527/// struct ApiDoc;
1528///```
1529///
1530/// _**Define info attribute values used to override auto generated ones from Cargo environment
1531/// variables.**_
1532/// ```compile_fail
1533/// # use utoipa::OpenApi;
1534/// #[derive(OpenApi)]
1535/// #[openapi(info(
1536/// title = "title override",
1537/// description = include_str!("./path/to/content"), // fail compile cause no such file
1538/// contact(name = "Test")
1539/// ))]
1540/// struct ApiDoc;
1541/// ```
1542///
1543/// _**Create OpenAPI with reusable response.**_
1544/// ```rust
1545/// #[derive(utoipa::ToSchema)]
1546/// struct Person {
1547/// name: String,
1548/// }
1549///
1550/// /// Person list response
1551/// #[derive(utoipa::ToResponse)]
1552/// struct PersonList(Vec<Person>);
1553///
1554/// #[utoipa::path(
1555/// get,
1556/// path = "/person-list",
1557/// responses(
1558/// (status = 200, response = PersonList)
1559/// )
1560/// )]
1561/// fn get_persons() -> Vec<Person> {
1562/// vec![]
1563/// }
1564///
1565/// #[derive(utoipa::OpenApi)]
1566/// #[openapi(
1567/// components(
1568/// schemas(Person),
1569/// responses(PersonList)
1570/// )
1571/// )]
1572/// struct ApiDoc;
1573/// ```
1574///
1575/// [openapi]: trait.OpenApi.html
1576/// [openapi_struct]: openapi/struct.OpenApi.html
1577/// [to_schema]: derive.ToSchema.html
1578/// [path]: attr.path.html
1579/// [modify]: trait.Modify.html
1580/// [info]: openapi/info/struct.Info.html
1581/// [security]: openapi/security/struct.SecurityRequirement.html
1582/// [path_security]: attr.path.html#security-requirement-attributes
1583/// [tags]: openapi/tag/struct.Tag.html
1584/// [to_response_trait]: trait.ToResponse.html
1585/// [servers]: openapi/server/index.html
1586pub fn openapi(input: TokenStream) -> TokenStream {
1587 let DeriveInput { attrs, ident, .. } = syn::parse_macro_input!(input);
1588
1589 let openapi_attributes = openapi::parse_openapi_attrs(&attrs).expect_or_abort(
1590 "expected #[openapi(...)] attribute to be present when used with OpenApi derive trait",
1591 );
1592
1593 let openapi = OpenApi(openapi_attributes, ident);
1594
1595 openapi.to_token_stream().into()
1596}
1597
1598#[proc_macro_error]
1599#[proc_macro_derive(IntoParams, attributes(param, into_params))]
1600/// Generate [path parameters][path_params] from struct's
1601/// fields.
1602///
1603/// This is `#[derive]` implementation for [`IntoParams`][into_params] trait.
1604///
1605/// Typically path parameters need to be defined within [`#[utoipa::path(...params(...))]`][path_params] section
1606/// for the endpoint. But this trait eliminates the need for that when [`struct`][struct]s are used to define parameters.
1607/// Still [`std::primitive`] and [`String`](std::string::String) path parameters or [`tuple`] style path parameters need to be defined
1608/// within `params(...)` section if description or other than default configuration need to be given.
1609///
1610/// You can use the Rust's own `#[deprecated]` attribute on field to mark it as
1611/// deprecated and it will reflect to the generated OpenAPI spec.
1612///
1613/// `#[deprecated]` attribute supports adding additional details such as a reason and or since version
1614/// but this is is not supported in OpenAPI. OpenAPI has only a boolean flag to determine deprecation.
1615/// While it is totally okay to declare deprecated with reason
1616/// `#[deprecated = "There is better way to do this"]` the reason would not render in OpenAPI spec.
1617///
1618/// Doc comment on struct fields will be used as description for the generated parameters.
1619/// ```rust
1620/// #[derive(utoipa::IntoParams)]
1621/// struct Query {
1622/// /// Query todo items by name.
1623/// name: String
1624/// }
1625/// ```
1626///
1627/// # IntoParams Container Attributes for `#[into_params(...)]`
1628///
1629/// The following attributes are available for use in on the container attribute `#[into_params(...)]` for the struct
1630/// deriving `IntoParams`:
1631///
1632/// * `names(...)` Define comma separated list of names for unnamed fields of struct used as a path parameter.
1633/// __Only__ supported on __unnamed structs__.
1634/// * `style = ...` Defines how all parameters are serialized by [`ParameterStyle`][style]. Default
1635/// values are based on _`parameter_in`_ attribute.
1636/// * `parameter_in = ...` = Defines where the parameters of this field are used with a value from
1637/// [`openapi::path::ParameterIn`][in_enum]. There is no default value, if this attribute is not
1638/// supplied, then the value is determined by the `parameter_in_provider` in
1639/// [`IntoParams::into_params()`](trait.IntoParams.html#tymethod.into_params).
1640/// * `rename_all = ...` Can be provided to alternatively to the serde's `rename_all` attribute. Effectively provides same functionality.
1641///
1642/// Use `names` to define name for single unnamed argument.
1643/// ```rust
1644/// # use utoipa::IntoParams;
1645/// #
1646/// #[derive(IntoParams)]
1647/// #[into_params(names("id"))]
1648/// struct Id(u64);
1649/// ```
1650///
1651/// Use `names` to define names for multiple unnamed arguments.
1652/// ```rust
1653/// # use utoipa::IntoParams;
1654/// #
1655/// #[derive(IntoParams)]
1656/// #[into_params(names("id", "name"))]
1657/// struct IdAndName(u64, String);
1658/// ```
1659///
1660/// # IntoParams Field Attributes for `#[param(...)]`
1661///
1662/// The following attributes are available for use in the `#[param(...)]` on struct fields:
1663///
1664/// * `style = ...` Defines how the parameter is serialized by [`ParameterStyle`][style]. Default values are based on _`parameter_in`_ attribute.
1665///
1666/// * `explode` Defines whether new _`parameter=value`_ pair is created for each parameter within _`object`_ or _`array`_.
1667///
1668/// * `allow_reserved` Defines whether reserved characters _`:/?#[]@!$&'()*+,;=`_ is allowed within value.
1669///
1670/// * `example = ...` Can be method reference or _`json!(...)`_. Given example
1671/// will override any example in underlying parameter type.
1672///
1673/// * `value_type = ...` Can be used to override default type derived from type of the field used in OpenAPI spec.
1674/// This is useful in cases where the default type does not correspond to the actual type e.g. when
1675/// any third-party types are used which are not [`ToSchema`][to_schema]s nor [`primitive` types][primitive].
1676/// The value can be any Rust type what normally could be used to serialize to JSON, or either virtual type _`Object`_
1677/// or _`Value`_, or an alias defined using `#[aliases(..)]`.
1678/// _`Object`_ will be rendered as generic OpenAPI object _(`type: object`)_.
1679/// _`Value`_ will be rendered as any OpenAPI value (i.e. no `type` restriction).
1680///
1681/// * `inline` If set, the schema for this field's type needs to be a [`ToSchema`][to_schema], and
1682/// the schema definition will be inlined.
1683///
1684/// * `default = ...` Can be method reference or _`json!(...)`_.
1685///
1686/// * `format = ...` May either be variant of the [`KnownFormat`][known_format] enum, or otherwise
1687/// an open value as a string. By default the format is derived from the type of the property
1688/// according OpenApi spec.
1689///
1690/// * `write_only` Defines property is only used in **write** operations *POST,PUT,PATCH* but not in *GET*
1691///
1692/// * `read_only` Defines property is only used in **read** operations *GET* but not in *POST,PUT,PATCH*
1693///
1694/// * `xml(...)` Can be used to define [`Xml`][xml] object properties applicable to named fields.
1695/// See configuration options at xml attributes of [`ToSchema`][to_schema_xml]
1696///
1697/// * `nullable` Defines property is nullable (note this is different to non-required).
1698///
1699/// * `required = ...` Can be used to enforce required status for the parameter. [See
1700/// rules][derive@IntoParams#field-nullability-and-required-rules]
1701///
1702/// * `rename = ...` Can be provided to alternatively to the serde's `rename` attribute. Effectively provides same functionality.
1703///
1704/// * `multiple_of = ...` Can be used to define multiplier for a value. Value is considered valid
1705/// division will result an `integer`. Value must be strictly above _`0`_.
1706///
1707/// * `maximum = ...` Can be used to define inclusive upper bound to a `number` value.
1708///
1709/// * `minimum = ...` Can be used to define inclusive lower bound to a `number` value.
1710///
1711/// * `exclusive_maximum = ...` Can be used to define exclusive upper bound to a `number` value.
1712///
1713/// * `exclusive_minimum = ...` Can be used to define exclusive lower bound to a `number` value.
1714///
1715/// * `max_length = ...` Can be used to define maximum length for `string` types.
1716///
1717/// * `min_length = ...` Can be used to define minimum length for `string` types.
1718///
1719/// * `pattern = ...` Can be used to define valid regular expression in _ECMA-262_ dialect the field value must match.
1720///
1721/// * `max_items = ...` Can be used to define maximum items allowed for `array` fields. Value must
1722/// be non-negative integer.
1723///
1724/// * `min_items = ...` Can be used to define minimum items allowed for `array` fields. Value must
1725/// be non-negative integer.
1726///
1727/// * `schema_with = ...` Use _`schema`_ created by provided function reference instead of the
1728/// default derived _`schema`_. The function must match to `fn() -> Into<RefOr<Schema>>`. It does
1729/// not accept arguments and must return anything that can be converted into `RefOr<Schema>`.
1730///
1731/// * `additional_properties = ...` Can be used to define free form types for maps such as
1732/// [`HashMap`](std::collections::HashMap) and [`BTreeMap`](std::collections::BTreeMap).
1733/// Free form type enables use of arbitrary types within map values.
1734/// Supports formats _`additional_properties`_ and _`additional_properties = true`_.
1735///
1736/// #### Field nullability and required rules
1737///
1738/// Same rules for nullability and required status apply for _`IntoParams`_ field attributes as for
1739/// _`ToSchema`_ field attributes. [See the rules][`derive@ToSchema#field-nullability-and-required-rules`].
1740///
1741/// # Partial `#[serde(...)]` attributes support
1742///
1743/// IntoParams derive has partial support for [serde attributes]. These supported attributes will reflect to the
1744/// generated OpenAPI doc. The following attributes are currently supported:
1745///
1746/// * `rename_all = "..."` Supported at the container level.
1747/// * `rename = "..."` Supported **only** at the field level.
1748/// * `default` Supported at the container level and field level according to [serde attributes].
1749/// * `skip_serializing_if = "..."` Supported **only** at the field level.
1750/// * `with = ...` Supported **only** at field level.
1751/// * `skip_serializing = "..."` Supported **only** at the field or variant level.
1752/// * `skip_deserializing = "..."` Supported **only** at the field or variant level.
1753/// * `skip = "..."` Supported **only** at the field level.
1754///
1755/// Other _`serde`_ attributes will impact the serialization but will not be reflected on the generated OpenAPI doc.
1756///
1757/// # Examples
1758///
1759/// _**Demonstrate [`IntoParams`][into_params] usage with resolving `Path` and `Query` parameters
1760/// with _`actix-web`_**_.
1761/// ```rust
1762/// use actix_web::{get, HttpResponse, Responder};
1763/// use actix_web::web::{Path, Query};
1764/// use serde::Deserialize;
1765/// use serde_json::json;
1766/// use utoipa::IntoParams;
1767///
1768/// #[derive(Deserialize, IntoParams)]
1769/// struct PetPathArgs {
1770/// /// Id of pet
1771/// id: i64,
1772/// /// Name of pet
1773/// name: String,
1774/// }
1775///
1776/// #[derive(Deserialize, IntoParams)]
1777/// struct Filter {
1778/// /// Age filter for pets
1779/// #[deprecated]
1780/// #[param(style = Form, explode, allow_reserved, example = json!([10]))]
1781/// age: Option<Vec<i32>>,
1782/// }
1783///
1784/// #[utoipa::path(
1785/// params(PetPathArgs, Filter),
1786/// responses(
1787/// (status = 200, description = "success response")
1788/// )
1789/// )]
1790/// #[get("/pet/{id}/{name}")]
1791/// async fn get_pet(pet: Path<PetPathArgs>, query: Query<Filter>) -> impl Responder {
1792/// HttpResponse::Ok().json(json!({ "id": pet.id }))
1793/// }
1794/// ```
1795///
1796/// _**Demonstrate [`IntoParams`][into_params] usage with the `#[into_params(...)]` container attribute to
1797/// be used as a path query, and inlining a schema query field:**_
1798/// ```rust
1799/// use serde::Deserialize;
1800/// use utoipa::{IntoParams, ToSchema};
1801///
1802/// #[derive(Deserialize, ToSchema)]
1803/// #[serde(rename_all = "snake_case")]
1804/// enum PetKind {
1805/// Dog,
1806/// Cat,
1807/// }
1808///
1809/// #[derive(Deserialize, IntoParams)]
1810/// #[into_params(style = Form, parameter_in = Query)]
1811/// struct PetQuery {
1812/// /// Name of pet
1813/// name: Option<String>,
1814/// /// Age of pet
1815/// age: Option<i32>,
1816/// /// Kind of pet
1817/// #[param(inline)]
1818/// kind: PetKind
1819/// }
1820///
1821/// #[utoipa::path(
1822/// get,
1823/// path = "/get_pet",
1824/// params(PetQuery),
1825/// responses(
1826/// (status = 200, description = "success response")
1827/// )
1828/// )]
1829/// async fn get_pet(query: PetQuery) {
1830/// // ...
1831/// }
1832/// ```
1833///
1834/// _**Override `String` with `i64` using `value_type` attribute.**_
1835/// ```rust
1836/// # use utoipa::IntoParams;
1837/// #
1838/// #[derive(IntoParams)]
1839/// #[into_params(parameter_in = Query)]
1840/// struct Filter {
1841/// #[param(value_type = i64)]
1842/// id: String,
1843/// }
1844/// ```
1845///
1846/// _**Override `String` with `Object` using `value_type` attribute. _`Object`_ will render as `type: object` in OpenAPI spec.**_
1847/// ```rust
1848/// # use utoipa::IntoParams;
1849/// #
1850/// #[derive(IntoParams)]
1851/// #[into_params(parameter_in = Query)]
1852/// struct Filter {
1853/// #[param(value_type = Object)]
1854/// id: String,
1855/// }
1856/// ```
1857///
1858/// _**You can use a generic type to override the default type of the field.**_
1859/// ```rust
1860/// # use utoipa::IntoParams;
1861/// #
1862/// #[derive(IntoParams)]
1863/// #[into_params(parameter_in = Query)]
1864/// struct Filter {
1865/// #[param(value_type = Option<String>)]
1866/// id: String
1867/// }
1868/// ```
1869///
1870/// _**You can even override a [`Vec`] with another one.**_
1871/// ```rust
1872/// # use utoipa::IntoParams;
1873/// #
1874/// #[derive(IntoParams)]
1875/// #[into_params(parameter_in = Query)]
1876/// struct Filter {
1877/// #[param(value_type = Vec<i32>)]
1878/// id: Vec<String>
1879/// }
1880/// ```
1881///
1882/// _**We can override value with another [`ToSchema`][to_schema].**_
1883/// ```rust
1884/// # use utoipa::{IntoParams, ToSchema};
1885/// #
1886/// #[derive(ToSchema)]
1887/// struct Id {
1888/// value: i64,
1889/// }
1890///
1891/// #[derive(IntoParams)]
1892/// #[into_params(parameter_in = Query)]
1893/// struct Filter {
1894/// #[param(value_type = Id)]
1895/// id: String
1896/// }
1897/// ```
1898///
1899/// _**Example with validation attributes.**_
1900/// ```rust
1901/// #[derive(utoipa::IntoParams)]
1902/// struct Item {
1903/// #[param(maximum = 10, minimum = 5, multiple_of = 2.5)]
1904/// id: i32,
1905/// #[param(max_length = 10, min_length = 5, pattern = "[a-z]*")]
1906/// value: String,
1907/// #[param(max_items = 5, min_items = 1)]
1908/// items: Vec<String>,
1909/// }
1910/// ````
1911///
1912/// _**Use `schema_with` to manually implement schema for a field.**_
1913/// ```rust
1914/// # use utoipa::openapi::schema::{Object, ObjectBuilder};
1915/// fn custom_type() -> Object {
1916/// ObjectBuilder::new()
1917/// .schema_type(utoipa::openapi::SchemaType::String)
1918/// .format(Some(utoipa::openapi::SchemaFormat::Custom(
1919/// "email".to_string(),
1920/// )))
1921/// .description(Some("this is the description"))
1922/// .build()
1923/// }
1924///
1925/// #[derive(utoipa::IntoParams)]
1926/// #[into_params(parameter_in = Query)]
1927/// struct Query {
1928/// #[param(schema_with = custom_type)]
1929/// email: String,
1930/// }
1931/// ```
1932///
1933/// [to_schema]: trait.ToSchema.html
1934/// [known_format]: openapi/schema/enum.KnownFormat.html
1935/// [xml]: openapi/xml/struct.Xml.html
1936/// [into_params]: trait.IntoParams.html
1937/// [path_params]: attr.path.html#params-attributes
1938/// [struct]: https://doc.rust-lang.org/std/keyword.struct.html
1939/// [style]: openapi/path/enum.ParameterStyle.html
1940/// [in_enum]: openapi/path/enum.ParameterIn.html
1941/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
1942/// [serde attributes]: https://serde.rs/attributes.html
1943/// [to_schema_xml]: macro@ToSchema#xml-attribute-configuration-options
1944pub fn into_params(input: TokenStream) -> TokenStream {
1945 let DeriveInput {
1946 attrs,
1947 ident,
1948 generics,
1949 data,
1950 ..
1951 } = syn::parse_macro_input!(input);
1952
1953 let into_params = IntoParams {
1954 attrs,
1955 generics,
1956 data,
1957 ident,
1958 };
1959
1960 into_params.to_token_stream().into()
1961}
1962
1963#[proc_macro_error]
1964#[proc_macro_derive(ToResponse, attributes(response, content, to_schema))]
1965/// Generate reusable OpenAPI response what can be used
1966/// in [`utoipa::path`][path] or in [`OpenApi`][openapi].
1967///
1968/// This is `#[derive]` implementation for [`ToResponse`][to_response] trait.
1969///
1970///
1971/// _`#[response]`_ attribute can be used to alter and add [response attributes](#toresponse-response-attributes).
1972///
1973/// _`#[content]`_ attributes is used to make enum variant a content of a specific type for the
1974/// response.
1975///
1976/// _`#[to_schema]`_ attribute is used to inline a schema for a response in unnamed structs or
1977/// enum variants with `#[content]` attribute. **Note!** [`ToSchema`] need to be implemented for
1978/// the field or variant type.
1979///
1980/// Type derived with _`ToResponse`_ uses provided doc comment as a description for the response. It
1981/// can alternatively be overridden with _`description = ...`_ attribute.
1982///
1983/// _`ToResponse`_ can be used in four different ways to generate OpenAPI response component.
1984///
1985/// 1. By decorating `struct` or `enum` with [`derive@ToResponse`] derive macro. This will create a
1986/// response with inlined schema resolved from the fields of the `struct` or `variants` of the
1987/// enum.
1988///
1989/// ```rust
1990/// # use utoipa::ToResponse;
1991/// #[derive(ToResponse)]
1992/// #[response(description = "Person response returns single Person entity")]
1993/// struct Person {
1994/// name: String,
1995/// }
1996/// ```
1997///
1998/// 2. By decorating unnamed field `struct` with [`derive@ToResponse`] derive macro. Unnamed field struct
1999/// allows users to use new type pattern to define one inner field which is used as a schema for
2000/// the generated response. This allows users to define `Vec` and `Option` response types.
2001/// Additionally these types can also be used with `#[to_schema]` attribute to inline the
2002/// field's type schema if it implements [`ToSchema`] derive macro.
2003///
2004/// ```rust
2005/// # #[derive(utoipa::ToSchema)]
2006/// # struct Person {
2007/// # name: String,
2008/// # }
2009/// /// Person list response
2010/// #[derive(utoipa::ToResponse)]
2011/// struct PersonList(Vec<Person>);
2012/// ```
2013///
2014/// 3. By decorating unit struct with [`derive@ToResponse`] derive macro. Unit structs will produce a
2015/// response without body.
2016///
2017/// ```rust
2018/// /// Success response which does not have body.
2019/// #[derive(utoipa::ToResponse)]
2020/// struct SuccessResponse;
2021/// ```
2022///
2023/// 4. By decorating `enum` with variants having `#[content(...)]` attribute. This allows users to
2024/// define multiple response content schemas to single response according to OpenAPI spec.
2025/// **Note!** Enum with _`content`_ attribute in variants cannot have enum level _`example`_ or
2026/// _`examples`_ defined. Instead examples need to be defined per variant basis. Additionally
2027/// these variants can also be used with `#[to_schema]` attribute to inline the variant's type schema
2028/// if it implements [`ToSchema`] derive macro.
2029///
2030/// ```rust
2031/// #[derive(utoipa::ToSchema)]
2032/// struct Admin {
2033/// name: String,
2034/// }
2035/// #[derive(utoipa::ToSchema)]
2036/// struct Admin2 {
2037/// name: String,
2038/// id: i32,
2039/// }
2040///
2041/// #[derive(utoipa::ToResponse)]
2042/// enum Person {
2043/// #[response(examples(
2044/// ("Person1" = (value = json!({"name": "name1"}))),
2045/// ("Person2" = (value = json!({"name": "name2"})))
2046/// ))]
2047/// Admin(#[content("application/vnd-custom-v1+json")] Admin),
2048///
2049/// #[response(example = json!({"name": "name3", "id": 1}))]
2050/// Admin2(#[content("application/vnd-custom-v2+json")] #[to_schema] Admin2),
2051/// }
2052/// ```
2053///
2054/// # ToResponse `#[response(...)]` attributes
2055///
2056/// * `description = "..."` Define description for the response as str. This can be used to
2057/// override the default description resolved from doc comments if present.
2058///
2059/// * `content_type = "..." | content_type = [...]` Can be used to override the default behavior of auto resolving the content type
2060/// from the `body` attribute. If defined the value should be valid content type such as
2061/// _`application/json`_. By default the content type is _`text/plain`_ for
2062/// [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and
2063/// _`application/json`_ for struct and complex enum types.
2064/// Content type can also be slice of **content_type** values if the endpoint support returning multiple
2065/// response content types. E.g _`["application/json", "text/xml"]`_ would indicate that endpoint can return both
2066/// _`json`_ and _`xml`_ formats. **The order** of the content types define the default example show first in
2067/// the Swagger UI. Swagger UI wil use the first _`content_type`_ value as a default example.
2068///
2069/// * `headers(...)` Slice of response headers that are returned back to a caller.
2070///
2071/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
2072/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2073///
2074/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
2075/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
2076/// * `name = ...` This is first attribute and value must be literal string.
2077/// * `summary = ...` Short description of example. Value must be literal string.
2078/// * `description = ...` Long description of example. Attribute supports markdown for rich text
2079/// representation. Value must be literal string.
2080/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
2081/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2082/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
2083/// the _`value`_ attribute. Value must be literal string.
2084///
2085/// _**Example of example definition.**_
2086/// ```text
2087/// ("John" = (summary = "This is John", value = json!({"name": "John"})))
2088/// ```
2089///
2090/// # Examples
2091///
2092/// _**Use reusable response in operation handler.**_
2093/// ```rust
2094/// #[derive(utoipa::ToResponse)]
2095/// struct PersonResponse {
2096/// value: String
2097/// }
2098///
2099/// #[derive(utoipa::OpenApi)]
2100/// #[openapi(components(responses(PersonResponse)))]
2101/// struct Doc;
2102///
2103/// #[utoipa::path(
2104/// get,
2105/// path = "/api/person",
2106/// responses(
2107/// (status = 200, response = PersonResponse)
2108/// )
2109/// )]
2110/// fn get_person() -> PersonResponse {
2111/// PersonResponse { value: "person".to_string() }
2112/// }
2113/// ```
2114///
2115/// _**Create a response from named struct.**_
2116/// ```rust
2117/// /// This is description
2118/// ///
2119/// /// It will also be used in `ToSchema` if present
2120/// #[derive(utoipa::ToSchema, utoipa::ToResponse)]
2121/// #[response(
2122/// description = "Override description for response",
2123/// content_type = "text/xml"
2124/// )]
2125/// #[response(
2126/// example = json!({"name": "the name"}),
2127/// headers(
2128/// ("csrf-token", description = "response csrf token"),
2129/// ("random-id" = i32)
2130/// )
2131/// )]
2132/// struct Person {
2133/// name: String,
2134/// }
2135/// ```
2136///
2137/// _**Create inlined person list response.**_
2138/// ```rust
2139/// # #[derive(utoipa::ToSchema)]
2140/// # struct Person {
2141/// # name: String,
2142/// # }
2143/// /// Person list response
2144/// #[derive(utoipa::ToResponse)]
2145/// struct PersonList(#[to_schema] Vec<Person>);
2146/// ```
2147///
2148/// _**Create enum response from variants.**_
2149/// ```rust
2150/// #[derive(utoipa::ToResponse)]
2151/// enum PersonType {
2152/// Value(String),
2153/// Foobar,
2154/// }
2155/// ```
2156///
2157/// [to_response]: trait.ToResponse.html
2158/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2159/// [path]: attr.path.html
2160/// [openapi]: derive.OpenApi.html
2161pub fn to_response(input: TokenStream) -> TokenStream {
2162 let DeriveInput {
2163 attrs,
2164 ident,
2165 generics,
2166 data,
2167 ..
2168 } = syn::parse_macro_input!(input);
2169
2170 let response = ToResponse::new(attrs, &data, generics, ident);
2171
2172 response.to_token_stream().into()
2173}
2174
2175#[proc_macro_error]
2176#[proc_macro_derive(
2177 IntoResponses,
2178 attributes(response, to_schema, ref_response, to_response)
2179)]
2180/// Generate responses with status codes what
2181/// can be attached to the [`utoipa::path`][path_into_responses].
2182///
2183/// This is `#[derive]` implementation of [`IntoResponses`][into_responses] trait. [`derive@IntoResponses`]
2184/// can be used to decorate _`structs`_ and _`enums`_ to generate response maps that can be used in
2185/// [`utoipa::path`][path_into_responses]. If _`struct`_ is decorated with [`derive@IntoResponses`] it will be
2186/// used to create a map of responses containing single response. Decorating _`enum`_ with
2187/// [`derive@IntoResponses`] will create a map of responses with a response for each variant of the _`enum`_.
2188///
2189/// Named field _`struct`_ decorated with [`derive@IntoResponses`] will create a response with inlined schema
2190/// generated from the body of the struct. This is a conveniency which allows users to directly
2191/// create responses with schemas without first creating a separate [response][to_response] type.
2192///
2193/// Unit _`struct`_ behaves similarly to then named field struct. Only difference is that it will create
2194/// a response without content since there is no inner fields.
2195///
2196/// Unnamed field _`struct`_ decorated with [`derive@IntoResponses`] will by default create a response with
2197/// referenced [schema][to_schema] if field is object or schema if type is [primitive
2198/// type][primitive]. _`#[to_schema]`_ attribute at field of unnamed _`struct`_ can be used to inline
2199/// the schema if type of the field implements [`ToSchema`][to_schema] trait. Alternatively
2200/// _`#[to_response]`_ and _`#[ref_response]`_ can be used at field to either reference a reusable
2201/// [response][to_response] or inline a reusable [response][to_response]. In both cases the field
2202/// type is expected to implement [`ToResponse`][to_response] trait.
2203///
2204///
2205/// Enum decorated with [`derive@IntoResponses`] will create a response for each variant of the _`enum`_.
2206/// Each variant must have it's own _`#[response(...)]`_ definition. Unit variant will behave same
2207/// as unit _`struct`_ by creating a response without content. Similarly named field variant and
2208/// unnamed field variant behaves the same as it was named field _`struct`_ and unnamed field
2209/// _`struct`_.
2210///
2211/// _`#[response]`_ attribute can be used at named structs, unnamed structs, unit structs and enum
2212/// variants to alter [response attributes](#intoresponses-response-attributes) of responses.
2213///
2214/// Doc comment on a _`struct`_ or _`enum`_ variant will be used as a description for the response.
2215/// It can also be overridden with _`description = "..."`_ attribute.
2216///
2217/// # IntoResponses `#[response(...)]` attributes
2218///
2219/// * `status = ...` Must be provided. Is either a valid http status code integer. E.g. _`200`_ or a
2220/// string value representing a range such as _`"4XX"`_ or `"default"` or a valid _`http::status::StatusCode`_.
2221/// _`StatusCode`_ can either be use path to the status code or _status code_ constant directly.
2222///
2223/// * `description = "..."` Define description for the response as str. This can be used to
2224/// override the default description resolved from doc comments if present.
2225///
2226/// * `content_type = "..." | content_type = [...]` Can be used to override the default behavior of auto resolving the content type
2227/// from the `body` attribute. If defined the value should be valid content type such as
2228/// _`application/json`_. By default the content type is _`text/plain`_ for
2229/// [primitive Rust types][primitive], `application/octet-stream` for _`[u8]`_ and
2230/// _`application/json`_ for struct and complex enum types.
2231/// Content type can also be slice of **content_type** values if the endpoint support returning multiple
2232/// response content types. E.g _`["application/json", "text/xml"]`_ would indicate that endpoint can return both
2233/// _`json`_ and _`xml`_ formats. **The order** of the content types define the default example show first in
2234/// the Swagger UI. Swagger UI wil use the first _`content_type`_ value as a default example.
2235///
2236/// * `headers(...)` Slice of response headers that are returned back to a caller.
2237///
2238/// * `example = ...` Can be _`json!(...)`_. _`json!(...)`_ should be something that
2239/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2240///
2241/// * `examples(...)` Define multiple examples for single response. This attribute is mutually
2242/// exclusive to the _`example`_ attribute and if both are defined this will override the _`example`_.
2243/// * `name = ...` This is first attribute and value must be literal string.
2244/// * `summary = ...` Short description of example. Value must be literal string.
2245/// * `description = ...` Long description of example. Attribute supports markdown for rich text
2246/// representation. Value must be literal string.
2247/// * `value = ...` Example value. It must be _`json!(...)`_. _`json!(...)`_ should be something that
2248/// _`serde_json::json!`_ can parse as a _`serde_json::Value`_.
2249/// * `external_value = ...` Define URI to literal example value. This is mutually exclusive to
2250/// the _`value`_ attribute. Value must be literal string.
2251///
2252/// _**Example of example definition.**_
2253/// ```text
2254/// ("John" = (summary = "This is John", value = json!({"name": "John"})))
2255/// ```
2256///
2257/// # Examples
2258///
2259/// _**Use `IntoResponses` to define [`utoipa::path`][path] responses.**_
2260/// ```rust
2261/// #[derive(utoipa::ToSchema)]
2262/// struct BadRequest {
2263/// message: String,
2264/// }
2265///
2266/// #[derive(utoipa::IntoResponses)]
2267/// enum UserResponses {
2268/// /// Success response
2269/// #[response(status = 200)]
2270/// Success { value: String },
2271///
2272/// #[response(status = 404)]
2273/// NotFound,
2274///
2275/// #[response(status = 400)]
2276/// BadRequest(BadRequest),
2277/// }
2278///
2279/// #[utoipa::path(
2280/// get,
2281/// path = "/api/user",
2282/// responses(
2283/// UserResponses
2284/// )
2285/// )]
2286/// fn get_user() -> UserResponses {
2287/// UserResponses::NotFound
2288/// }
2289/// ```
2290/// _**Named struct response with inlined schema.**_
2291/// ```rust
2292/// /// This is success response
2293/// #[derive(utoipa::IntoResponses)]
2294/// #[response(status = 200)]
2295/// struct SuccessResponse {
2296/// value: String,
2297/// }
2298/// ```
2299///
2300/// _**Unit struct response without content.**_
2301/// ```rust
2302/// #[derive(utoipa::IntoResponses)]
2303/// #[response(status = NOT_FOUND)]
2304/// struct NotFound;
2305/// ```
2306///
2307/// _**Unnamed struct response with inlined response schema.**_
2308/// ```rust
2309/// # #[derive(utoipa::ToSchema)]
2310/// # struct Foo;
2311/// #[derive(utoipa::IntoResponses)]
2312/// #[response(status = 201)]
2313/// struct CreatedResponse(#[to_schema] Foo);
2314/// ```
2315///
2316/// _**Enum with multiple responses.**_
2317/// ```rust
2318/// # #[derive(utoipa::ToResponse)]
2319/// # struct Response {
2320/// # message: String,
2321/// # }
2322/// # #[derive(utoipa::ToSchema)]
2323/// # struct BadRequest {}
2324/// #[derive(utoipa::IntoResponses)]
2325/// enum UserResponses {
2326/// /// Success response description.
2327/// #[response(status = 200)]
2328/// Success { value: String },
2329///
2330/// #[response(status = 404)]
2331/// NotFound,
2332///
2333/// #[response(status = 400)]
2334/// BadRequest(BadRequest),
2335///
2336/// #[response(status = 500)]
2337/// ServerError(#[ref_response] Response),
2338///
2339/// #[response(status = 418)]
2340/// TeaPot(#[to_response] Response),
2341/// }
2342/// ```
2343///
2344/// [into_responses]: trait.IntoResponses.html
2345/// [to_schema]: trait.ToSchema.html
2346/// [to_response]: trait.ToResponse.html
2347/// [path_into_responses]: attr.path.html#responses-from-intoresponses
2348/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2349/// [path]: macro@crate::path
2350pub fn into_responses(input: TokenStream) -> TokenStream {
2351 let DeriveInput {
2352 attrs,
2353 ident,
2354 generics,
2355 data,
2356 ..
2357 } = syn::parse_macro_input!(input);
2358
2359 let into_responses = IntoResponses {
2360 attributes: attrs,
2361 ident,
2362 generics,
2363 data,
2364 };
2365
2366 into_responses.to_token_stream().into()
2367}
2368
2369/// Create OpenAPI Schema from arbitrary type.
2370///
2371/// This macro provides a quick way to render arbitrary types as OpenAPI Schema Objects. It
2372/// supports two call formats.
2373/// 1. With type only
2374/// 2. With _`#[inline]`_ attribute to inline the referenced schemas.
2375///
2376/// By default the macro will create references `($ref)` for non primitive types like _`Pet`_.
2377/// However when used with _`#[inline]`_ the non [`primitive`][primitive] type schemas will
2378/// be inlined to the schema output.
2379///
2380/// ```rust
2381/// # #[derive(utoipa::ToSchema)]
2382/// # struct Pet {id: i32};
2383/// let schema = utoipa::schema!(Vec<Pet>);
2384///
2385/// // with inline
2386/// let schema = utoipa::schema!(#[inline] Vec<Pet>);
2387/// ```
2388///
2389/// # Examples
2390///
2391/// _**Create vec of pets schema.**_
2392/// ```rust
2393/// # use utoipa::openapi::schema::{Schema, Array, Object, ObjectBuilder, SchemaFormat,
2394/// # KnownFormat, SchemaType};
2395/// # use utoipa::openapi::RefOr;
2396/// #[derive(utoipa::ToSchema)]
2397/// struct Pet {
2398/// id: i32,
2399/// name: String,
2400/// }
2401///
2402/// let schema: RefOr<Schema> = utoipa::schema!(#[inline] Vec<Pet>).into();
2403/// // will output
2404/// let generated = RefOr::T(Schema::Array(
2405/// Array::new(
2406/// ObjectBuilder::new()
2407/// .property("id", ObjectBuilder::new()
2408/// .schema_type(SchemaType::Integer)
2409/// .format(Some(SchemaFormat::KnownFormat(KnownFormat::Int32)))
2410/// .build())
2411/// .required("id")
2412/// .property("name", Object::with_type(SchemaType::String))
2413/// .required("name")
2414/// )
2415/// ));
2416/// # assert_json_diff::assert_json_eq!(serde_json::to_value(&schema).unwrap(), serde_json::to_value(&generated).unwrap());
2417/// ```
2418///
2419/// [primitive]: https://doc.rust-lang.org/std/primitive/index.html
2420#[proc_macro]
2421pub fn schema(input: TokenStream) -> TokenStream {
2422 struct Schema {
2423 inline: bool,
2424 ty: syn::Type,
2425 }
2426 impl Parse for Schema {
2427 fn parse(input: ParseStream) -> syn::Result<Self> {
2428 let inline = if input.peek(Token![#]) && input.peek2(Bracket) {
2429 input.parse::<Token![#]>()?;
2430
2431 let inline;
2432 bracketed!(inline in input);
2433 let i = inline.parse::<Ident>()?;
2434 i == "inline"
2435 } else {
2436 false
2437 };
2438
2439 let ty = input.parse()?;
2440
2441 Ok(Self { inline, ty })
2442 }
2443 }
2444
2445 let schema = syn::parse_macro_input!(input as Schema);
2446 let type_tree = TypeTree::from_type(&schema.ty);
2447
2448 let schema = ComponentSchema::new(ComponentSchemaProps {
2449 features: Some(vec![Feature::Inline(schema.inline.into())]),
2450 type_tree: &type_tree,
2451 deprecated: None,
2452 description: None,
2453 object_name: "",
2454 });
2455
2456 schema.to_token_stream().into()
2457}
2458
2459/// Tokenizes slice or Vec of tokenizable items as array either with reference (`&[...]`)
2460/// or without correctly to OpenAPI JSON.
2461#[cfg_attr(feature = "debug", derive(Debug))]
2462enum Array<'a, T>
2463where
2464 T: Sized + ToTokens,
2465{
2466 Owned(Vec<T>),
2467 #[allow(dead_code)]
2468 Borrowed(&'a [T]),
2469}
2470
2471impl<T> Array<'_, T> where T: ToTokens + Sized {}
2472
2473impl<V> FromIterator<V> for Array<'_, V>
2474where
2475 V: Sized + ToTokens,
2476{
2477 fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
2478 Self::Owned(iter.into_iter().collect())
2479 }
2480}
2481
2482impl<'a, T> Deref for Array<'a, T>
2483where
2484 T: Sized + ToTokens,
2485{
2486 type Target = [T];
2487
2488 fn deref(&self) -> &Self::Target {
2489 match self {
2490 Self::Owned(vec) => vec.as_slice(),
2491 Self::Borrowed(slice) => slice,
2492 }
2493 }
2494}
2495
2496impl<T> ToTokens for Array<'_, T>
2497where
2498 T: Sized + ToTokens,
2499{
2500 fn to_tokens(&self, tokens: &mut TokenStream2) {
2501 let values = match self {
2502 Self::Owned(values) => values.iter(),
2503 Self::Borrowed(values) => values.iter(),
2504 };
2505
2506 tokens.append(Group::new(
2507 proc_macro2::Delimiter::Bracket,
2508 values
2509 .fold(Punctuated::new(), |mut punctuated, item| {
2510 punctuated.push_value(item);
2511 punctuated.push_punct(Punct::new(',', proc_macro2::Spacing::Alone));
2512
2513 punctuated
2514 })
2515 .to_token_stream(),
2516 ));
2517 }
2518}
2519
2520#[cfg_attr(feature = "debug", derive(Debug))]
2521enum Deprecated {
2522 True,
2523 False,
2524}
2525
2526impl From<bool> for Deprecated {
2527 fn from(bool: bool) -> Self {
2528 if bool {
2529 Self::True
2530 } else {
2531 Self::False
2532 }
2533 }
2534}
2535
2536impl ToTokens for Deprecated {
2537 fn to_tokens(&self, tokens: &mut TokenStream2) {
2538 tokens.extend(match self {
2539 Self::False => quote! { utoipa::openapi::Deprecated::False },
2540 Self::True => quote! { utoipa::openapi::Deprecated::True },
2541 })
2542 }
2543}
2544
2545#[derive(PartialEq, Eq)]
2546#[cfg_attr(feature = "debug", derive(Debug))]
2547enum Required {
2548 True,
2549 False,
2550}
2551
2552impl From<bool> for Required {
2553 fn from(bool: bool) -> Self {
2554 if bool {
2555 Self::True
2556 } else {
2557 Self::False
2558 }
2559 }
2560}
2561
2562impl From<features::Required> for Required {
2563 fn from(value: features::Required) -> Self {
2564 let features::Required(required) = value;
2565 crate::Required::from(required)
2566 }
2567}
2568
2569impl ToTokens for Required {
2570 fn to_tokens(&self, tokens: &mut TokenStream2) {
2571 tokens.extend(match self {
2572 Self::False => quote! { utoipa::openapi::Required::False },
2573 Self::True => quote! { utoipa::openapi::Required::True },
2574 })
2575 }
2576}
2577
2578#[derive(Default)]
2579#[cfg_attr(feature = "debug", derive(Debug))]
2580struct ExternalDocs {
2581 url: String,
2582 description: Option<String>,
2583}
2584
2585impl Parse for ExternalDocs {
2586 fn parse(input: ParseStream) -> syn::Result<Self> {
2587 const EXPECTED_ATTRIBUTE: &str = "unexpected attribute, expected any of: url, description";
2588
2589 let mut external_docs = ExternalDocs::default();
2590
2591 while !input.is_empty() {
2592 let ident = input.parse::<Ident>().map_err(|error| {
2593 syn::Error::new(error.span(), format!("{EXPECTED_ATTRIBUTE}, {error}"))
2594 })?;
2595 let attribute_name = &*ident.to_string();
2596
2597 match attribute_name {
2598 "url" => {
2599 external_docs.url = parse_utils::parse_next_literal_str(input)?;
2600 }
2601 "description" => {
2602 external_docs.description = Some(parse_utils::parse_next_literal_str(input)?);
2603 }
2604 _ => return Err(syn::Error::new(ident.span(), EXPECTED_ATTRIBUTE)),
2605 }
2606
2607 if !input.is_empty() {
2608 input.parse::<Token![,]>()?;
2609 }
2610 }
2611
2612 Ok(external_docs)
2613 }
2614}
2615
2616impl ToTokens for ExternalDocs {
2617 fn to_tokens(&self, tokens: &mut TokenStream2) {
2618 let url = &self.url;
2619 tokens.extend(quote! {
2620 utoipa::openapi::external_docs::ExternalDocsBuilder::new()
2621 .url(#url)
2622 });
2623
2624 if let Some(ref description) = self.description {
2625 tokens.extend(quote! {
2626 .description(Some(#description))
2627 });
2628 }
2629
2630 tokens.extend(quote! { .build() })
2631 }
2632}
2633
2634/// Represents OpenAPI Any value used in example and default fields.
2635#[derive(Clone)]
2636#[cfg_attr(feature = "debug", derive(Debug))]
2637pub(self) enum AnyValue {
2638 String(TokenStream2),
2639 Json(TokenStream2),
2640 DefaultTrait {
2641 struct_ident: Ident,
2642 field_ident: Member,
2643 },
2644}
2645
2646impl AnyValue {
2647 /// Parse `json!(...)` as [`AnyValue::Json`]
2648 fn parse_json(input: ParseStream) -> syn::Result<Self> {
2649 parse_utils::parse_json_token_stream(input).map(AnyValue::Json)
2650 }
2651
2652 fn parse_any(input: ParseStream) -> syn::Result<Self> {
2653 if input.peek(Lit) {
2654 if input.peek(LitStr) {
2655 let lit_str = input.parse::<LitStr>().unwrap().to_token_stream();
2656
2657 Ok(AnyValue::Json(lit_str))
2658 } else {
2659 let lit = input.parse::<Lit>().unwrap().to_token_stream();
2660
2661 Ok(AnyValue::Json(lit))
2662 }
2663 } else {
2664 let fork = input.fork();
2665 let is_json = if fork.peek(syn::Ident) && fork.peek2(Token![!]) {
2666 let ident = fork.parse::<Ident>().unwrap();
2667 ident == "json"
2668 } else {
2669 false
2670 };
2671
2672 if is_json {
2673 let json = parse_utils::parse_json_token_stream(input)?;
2674
2675 Ok(AnyValue::Json(json))
2676 } else {
2677 let method = input.parse::<ExprPath>().map_err(|error| {
2678 syn::Error::new(
2679 error.span(),
2680 "expected literal value, json!(...) or method reference",
2681 )
2682 })?;
2683
2684 Ok(AnyValue::Json(quote! { #method() }))
2685 }
2686 }
2687 }
2688
2689 fn parse_lit_str_or_json(input: ParseStream) -> syn::Result<Self> {
2690 if input.peek(LitStr) {
2691 Ok(AnyValue::String(
2692 input.parse::<LitStr>().unwrap().to_token_stream(),
2693 ))
2694 } else {
2695 Ok(AnyValue::Json(parse_utils::parse_json_token_stream(input)?))
2696 }
2697 }
2698
2699 fn new_default_trait(struct_ident: Ident, field_ident: Member) -> Self {
2700 Self::DefaultTrait {
2701 struct_ident,
2702 field_ident,
2703 }
2704 }
2705}
2706
2707impl ToTokens for AnyValue {
2708 fn to_tokens(&self, tokens: &mut TokenStream2) {
2709 match self {
2710 Self::Json(json) => tokens.extend(quote! {
2711 serde_json::json!(#json)
2712 }),
2713 Self::String(string) => string.to_tokens(tokens),
2714 Self::DefaultTrait {
2715 struct_ident,
2716 field_ident,
2717 } => tokens.extend(quote! {
2718 serde_json::to_value(#struct_ident::default().#field_ident).unwrap()
2719 }),
2720 }
2721 }
2722}
2723
2724trait ResultExt<T> {
2725 fn unwrap_or_abort(self) -> T;
2726 fn expect_or_abort(self, message: &str) -> T;
2727}
2728
2729impl<T> ResultExt<T> for Result<T, syn::Error> {
2730 fn unwrap_or_abort(self) -> T {
2731 match self {
2732 Ok(value) => value,
2733 Err(error) => abort!(error.span(), format!("{error}")),
2734 }
2735 }
2736
2737 fn expect_or_abort(self, message: &str) -> T {
2738 match self {
2739 Ok(value) => value,
2740 Err(error) => abort!(error.span(), format!("{error}: {message}")),
2741 }
2742 }
2743}
2744
2745trait OptionExt<T> {
2746 fn expect_or_abort(self, message: &str) -> T;
2747}
2748
2749impl<T> OptionExt<T> for Option<T> {
2750 fn expect_or_abort(self, message: &str) -> T {
2751 self.unwrap_or_else(|| abort!(Span::call_site(), message))
2752 }
2753}
2754
2755/// Parsing utils
2756mod parse_utils {
2757 use proc_macro2::{Group, Ident, TokenStream};
2758 use syn::{
2759 parenthesized,
2760 parse::{Parse, ParseStream},
2761 punctuated::Punctuated,
2762 token::Comma,
2763 Error, LitBool, LitStr, Token,
2764 };
2765
2766 use crate::ResultExt;
2767
2768 pub fn parse_next<T: Sized>(input: ParseStream, next: impl FnOnce() -> T) -> T {
2769 input
2770 .parse::<Token![=]>()
2771 .expect_or_abort("expected equals token before value assignment");
2772 next()
2773 }
2774
2775 pub fn parse_next_literal_str(input: ParseStream) -> syn::Result<String> {
2776 Ok(parse_next(input, || input.parse::<LitStr>())?.value())
2777 }
2778
2779 pub fn parse_groups<T, R>(input: ParseStream) -> syn::Result<R>
2780 where
2781 T: Sized,
2782 T: Parse,
2783 R: FromIterator<T>,
2784 {
2785 Punctuated::<Group, Comma>::parse_terminated(input).and_then(|groups| {
2786 groups
2787 .into_iter()
2788 .map(|group| syn::parse2::<T>(group.stream()))
2789 .collect::<syn::Result<R>>()
2790 })
2791 }
2792
2793 pub fn parse_punctuated_within_parenthesis<T>(
2794 input: ParseStream,
2795 ) -> syn::Result<Punctuated<T, Comma>>
2796 where
2797 T: Parse,
2798 {
2799 let content;
2800 parenthesized!(content in input);
2801 Punctuated::<T, Comma>::parse_terminated(&content)
2802 }
2803
2804 pub fn parse_bool_or_true(input: ParseStream) -> syn::Result<bool> {
2805 if input.peek(Token![=]) && input.peek2(LitBool) {
2806 input.parse::<Token![=]>()?;
2807
2808 Ok(input.parse::<LitBool>()?.value())
2809 } else {
2810 Ok(true)
2811 }
2812 }
2813
2814 /// Parse `json!(...)` as a [`TokenStream`].
2815 pub fn parse_json_token_stream(input: ParseStream) -> syn::Result<TokenStream> {
2816 if input.peek(syn::Ident) && input.peek2(Token![!]) {
2817 input.parse::<Ident>().and_then(|ident| {
2818 if ident != "json" {
2819 return Err(Error::new(
2820 ident.span(),
2821 format!("unexpected token {ident}, expected: json!(...)"),
2822 ));
2823 }
2824
2825 Ok(ident)
2826 })?;
2827 input.parse::<Token![!]>()?;
2828
2829 Ok(input.parse::<Group>()?.stream())
2830 } else {
2831 Err(Error::new(
2832 input.span(),
2833 "unexpected token, expected json!(...)",
2834 ))
2835 }
2836 }
2837}