Derive Macro utoipa_gen::ToSchema
source · #[derive(ToSchema)]
{
// Attributes available to this derive:
#[schema]
#[aliases]
}
Expand description
Generate reusable OpenAPI schema to be used
together with OpenApi
.
This is #[derive]
implementation for ToSchema
trait. The macro accepts one
schema
attribute optionally which can be used to enhance generated documentation. The attribute can be placed
at item level or field level in struct and enums. Currently placing this attribute to unnamed field does
not have any effect.
You can use the Rust’s own #[deprecated]
attribute on any struct, enum or field to mark it as deprecated and it will
reflect to the generated OpenAPI spec.
#[deprecated]
attribute supports adding additional details such as a reason and or since version but this is is not supported in
OpenAPI. OpenAPI has only a boolean flag to determine deprecation. While it is totally okay to declare deprecated with reason
#[deprecated = "There is better way to do this"]
the reason would not render in OpenAPI spec.
Doc comments on fields will resolve to field descriptions in generated OpenAPI doc. On struct level doc comments will resolve to object descriptions.
/// This is a pet
#[derive(utoipa::ToSchema)]
struct Pet {
/// Name for your pet
name: String,
}
§Struct Optional Configuration Options for #[schema(...)]
example = ...
Can bejson!(...)
.json!(...)
should be something thatserde_json::json!
can parse as aserde_json::Value
.xml(...)
Can be used to defineXml
object properties applicable to Structs.title = ...
Literal string value. Can be used to define title for struct in OpenAPI document. Some OpenAPI code generation libraries also use this field as a name for the struct.rename_all = ...
Supports same syntax as serderename_all
attribute. Will rename all fields of the structs accordingly. If both serderename_all
and schemarename_all
are defined serde will take precedence.as = ...
Can be used to define alternative path and name for the schema what will be used in the OpenAPI. E.gas = path::to::Pet
. This would make the schema appear in the generated OpenAPI spec aspath.to.Pet
.default
Can be used to populate default values on all fields using the struct’sDefault
implementation.deprecated
Can be used to mark all fields as deprecated in the generated OpenAPI spec but not in the code. If you’d like to mark the fields as deprecated in the code as well use Rust’s own#[deprecated]
attribute instead.
§Enum Optional Configuration Options for #[schema(...)]
example = ...
Can be method reference orjson!(...)
.default = ...
Can be method reference orjson!(...)
.title = ...
Literal string value. Can be used to define title for enum in OpenAPI document. Some OpenAPI code generation libraries also use this field as a name for the enum. Note! Complex enum (enum with other than unit variants) does not support title!rename_all = ...
Supports same syntax as serderename_all
attribute. Will rename all variants of the enum accordingly. If both serderename_all
and schemarename_all
are defined serde will take precedence.as = ...
Can be used to define alternative path and name for the schema what will be used in the OpenAPI. E.gas = path::to::Pet
. This would make the schema appear in the generated OpenAPI spec aspath.to.Pet
.deprecated
Can be used to mark the enum as deprecated in the generated OpenAPI spec but not in the code. If you’d like to mark the enum as deprecated in the code as well use Rust’s own#[deprecated]
attribute instead.
§Enum Variant Optional Configuration Options for #[schema(...)]
Supports all variant specific configuration options e.g. if variant is UnnamedStruct
then
unnamed struct type configuration options are supported.
In addition to the variant type specific configuration options enum variants support custom
rename
attribute. It behaves similarly to serde’s rename
attribute. If both serde
rename
and schema rename
are defined serde will take precedence.
§Unnamed Field Struct Optional Configuration Options for #[schema(...)]
example = ...
Can be method reference orjson!(...)
.default = ...
Can be method reference orjson!(...)
. If no value is specified, and the struct has only one field, the field’s default value in the schema will be set from the struct’sDefault
implementation.format = ...
May either be variant of theKnownFormat
enum, or otherwise an open value as a string. By default the format is derived from the type of the property according OpenApi spec.value_type = ...
Can be used to override default type derived from type of the field used in OpenAPI spec. This is useful in cases where the default type does not correspond to the actual type e.g. when any third-party types are used which are notToSchema
s norprimitive
types. The value can be any Rust type what normally could be used to serialize to JSON or either virtual typeObject
orValue
, or an alias defined using#[aliases(..)]
.Object
will be rendered as generic OpenAPI object (type: object
).Value
will be rendered as any OpenAPI value (i.e. notype
restriction).title = ...
Literal string value. Can be used to define title for struct in OpenAPI document. Some OpenAPI code generation libraries also use this field as a name for the struct.as = ...
Can be used to define alternative path and name for the schema what will be used in the OpenAPI. E.gas = path::to::Pet
. This would make the schema appear in the generated OpenAPI spec aspath.to.Pet
.deprecated
Can be used to mark the field as deprecated in the generated OpenAPI spec but not in the code. If you’d like to mark the field as deprecated in the code as well use Rust’s own#[deprecated]
attribute instead.
§Named Fields Optional Configuration Options for #[schema(...)]
example = ...
Can be method reference orjson!(...)
.default = ...
Can be method reference orjson!(...)
.format = ...
May either be variant of theKnownFormat
enum, or otherwise an open value as a string. By default the format is derived from the type of the property according OpenApi spec.write_only
Defines property is only used in write operations POST,PUT,PATCH but not in GETread_only
Defines property is only used in read operations GET but not in POST,PUT,PATCHxml(...)
Can be used to defineXml
object properties applicable to named fields. See configuration options at xml attributes ofToSchema
value_type = ...
Can be used to override default type derived from type of the field used in OpenAPI spec. This is useful in cases where the default type does not correspond to the actual type e.g. when any third-party types are used which are notToSchema
s norprimitive
types. The value can be any Rust type what normally could be used to serialize to JSON, or either virtual typeObject
orValue
, or an alias defined using#[aliases(..)]
.Object
will be rendered as generic OpenAPI object (type: object
).Value
will be rendered as any OpenAPI value (i.e. notype
restriction).inline
If the type of this field implementsToSchema
, then the schema definition will be inlined. warning: Don’t use this for recursive data types!required = ...
Can be used to enforce required status for the field. See rulesnullable
Defines property is nullable (note this is different to non-required).rename = ...
Supports same syntax as serderename
attribute. Will rename field accordingly. If both serderename
and schemarename
are defined serde will take precedence.multiple_of = ...
Can be used to define multiplier for a value. Value is considered valid division will result aninteger
. Value must be strictly above0
.maximum = ...
Can be used to define inclusive upper bound to anumber
value.minimum = ...
Can be used to define inclusive lower bound to anumber
value.exclusive_maximum = ...
Can be used to define exclusive upper bound to anumber
value.exclusive_minimum = ...
Can be used to define exclusive lower bound to anumber
value.max_length = ...
Can be used to define maximum length forstring
types.min_length = ...
Can be used to define minimum length forstring
types.pattern = ...
Can be used to define valid regular expression in ECMA-262 dialect the field value must match.max_items = ...
Can be used to define maximum items allowed forarray
fields. Value must be non-negative integer.min_items = ...
Can be used to define minimum items allowed forarray
fields. Value must be non-negative integer.schema_with = ...
Useschema
created by provided function reference instead of the default derivedschema
. The function must match tofn() -> Into<RefOr<Schema>>
. It does not accept arguments and must return anything that can be converted intoRefOr<Schema>
.additional_properties = ...
Can be used to define free form types for maps such asHashMap
andBTreeMap
. Free form type enables use of arbitrary types within map values. Supports formatsadditional_properties
andadditional_properties = true
.deprecated
Can be used to mark the field as deprecated in the generated OpenAPI spec but not in the code. If you’d like to mark the field as deprecated in the code as well use Rust’s own#[deprecated]
attribute instead.
§Field nullability and required rules
Field is considered required
if
- it is not
Option
field - and it does not have
skip_serializing_if
property - and it does not have
serde_with
double_option
- and it does not have default value provided with serde
default
attribute
Field is considered nullable
when field type is Option
.
§Xml attribute Configuration Options
xml(name = "...")
Will set name for property or type.xml(namespace = "...")
Will set namespace for xml element which needs to be valid uri.xml(prefix = "...")
Will set prefix for name.xml(attribute)
Will translate property to xml attribute instead of xml element.xml(wrapped)
Will make wrapped xml element.xml(wrapped(name = "wrap_name"))
Will override the wrapper elements name.
See Xml
for more details.
§Partial #[serde(...)]
attributes support
ToSchema derive has partial support for serde attributes. These supported attributes will reflect to the
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
be serialized anyway. Similarly the rename
and rename_all
will reflect to the generated OpenAPI doc.
rename_all = "..."
Supported at the container level.rename = "..."
Supported only at the field or variant level.skip = "..."
Supported only at the field or variant level.skip_serializing = "..."
Supported only at the field or variant level.skip_deserializing = "..."
Supported only at the field or variant level.skip_serializing_if = "..."
Supported only at the field level.with = ...
Supported only at field level.tag = "..."
Supported at the container level.tag
attribute works as a discriminator field for an enum.content = "..."
Supported at the container level, allows adjacently-tagged enums. This attribute requires that atag
is present, otherwise serde will trigger a compile-time failure.untagged
Supported at the container level. Allows untagged enum representation.default
Supported at the container level and field level according to serde attributes.flatten
Supported at the field level.
Other serde
attributes works as is but does not have any effect on the generated OpenAPI doc.
Note! tag
attribute has some limitations like it cannot be used
with unnamed field structs and tuple types. See more at
enum representation docs.
Note! with
attribute is used in tandem with serde_with to recognize
double_option
from field value.
double_option
is only supported attribute from serde_with
crate.
#[derive(Serialize, ToSchema)]
struct Foo(String);
#[derive(Serialize, ToSchema)]
#[serde(rename_all = "camelCase")]
enum Bar {
UnitValue,
#[serde(rename_all = "camelCase")]
NamedFields {
#[serde(rename = "id")]
named_id: &'static str,
name_list: Option<Vec<String>>
},
UnnamedFields(Foo),
#[serde(skip)]
SkipMe,
}
Add custom tag
to change JSON representation to be internally tagged.
#[derive(Serialize, ToSchema)]
struct Foo(String);
#[derive(Serialize, ToSchema)]
#[serde(tag = "tag")]
enum Bar {
UnitValue,
NamedFields {
id: &'static str,
names: Option<Vec<String>>
},
}
Add serde default
attribute for MyValue struct. Similarly default
could be added to
individual fields as well. If default
is given the field’s affected will be treated
as optional.
#[derive(utoipa::ToSchema, serde::Deserialize, Default)]
#[serde(default)]
struct MyValue {
field: String
}
§#[repr(...)]
attribute support
Serde repr allows field-less enums be represented by their numeric value.
repr(u*)
for unsigned integer.repr(i*)
for signed integer.
Supported schema attributes
example = ...
Can be method reference orjson!(...)
.default = ...
Can be method reference orjson!(...)
.title = ...
Literal string value. Can be used to define title for enum in OpenAPI document. Some OpenAPI code generation libraries also use this field as a name for the enum. Note! Complex enum (enum with other than unit variants) does not support title!as = ...
Can be used to define alternative path and name for the schema what will be used in the OpenAPI. E.gas = path::to::Pet
. This would make the schema appear in the generated OpenAPI spec aspath.to.Pet
.
Create enum with numeric values.
#[derive(ToSchema)]
#[repr(u8)]
#[schema(default = default_value, example = 2)]
enum Mode {
One = 1,
Two,
}
fn default_value() -> u8 {
1
}
You can use skip
and tag
attributes from serde.
#[derive(ToSchema, serde::Serialize)]
#[repr(i8)]
#[serde(tag = "code")]
enum ExitCode {
Error = -1,
#[serde(skip)]
Unknown = 0,
Ok = 1,
}
§Generic schemas with aliases
Schemas can also be generic which allows reusing types. This enables certain behaviour patters where super type declares common code for type aliases.
In this example we have common Status
type which accepts one generic type. It is then defined
with #[aliases(...)]
that it is going to be used with String
and i32
values.
The generic argument could also be another ToSchema
as well.
#[derive(ToSchema)]
#[aliases(StatusMessage = Status<String>, StatusNumber = Status<i32>)]
struct Status<T> {
value: T
}
#[derive(OpenApi)]
#[openapi(
components(schemas(StatusMessage, StatusNumber))
)]
struct ApiDoc;
The #[aliases(...)]
is just syntactic sugar and will create Rust type aliases
behind the scenes which then can be later referenced anywhere in code.
Note! You should never register generic type itself in components(...)
so according above example Status<...>
should not be registered
because it will not render the type correctly and will cause an error in generated OpenAPI spec.
§Examples
Simple example of a Pet with descriptions and object level example.
/// This is a pet.
#[derive(ToSchema)]
#[schema(example = json!({"name": "bob the cat", "id": 0}))]
struct Pet {
/// Unique id of a pet.
id: u64,
/// Name of a pet.
name: String,
/// Age of a pet if known.
age: Option<i32>,
}
The schema
attribute can also be placed at field level as follows.
#[derive(ToSchema)]
struct Pet {
#[schema(example = 1, default = 0)]
id: u64,
name: String,
age: Option<i32>,
}
You can also use method reference for attribute values.
#[derive(ToSchema)]
struct Pet {
#[schema(example = u64::default, default = u64::default)]
id: u64,
#[schema(default = default_name)]
name: String,
age: Option<i32>,
}
fn default_name() -> String {
"bob".to_string()
}
For enums and unnamed field structs you can define schema
at type level.
#[derive(ToSchema)]
#[schema(example = "Bus")]
enum VehicleType {
Rocket, Car, Bus, Submarine
}
Also you write complex enum combining all above types.
#[derive(ToSchema)]
enum ErrorResponse {
InvalidCredentials,
#[schema(default = String::default, example = "Pet not found")]
NotFound(String),
System {
#[schema(example = "Unknown system failure")]
details: String,
}
}
It is possible to specify the title of each variant to help generators create named structures.
#[derive(ToSchema)]
enum ErrorResponse {
#[schema(title = "InvalidCredentials")]
InvalidCredentials,
#[schema(title = "NotFound")]
NotFound(String),
}
Use xml
attribute to manipulate xml output.
#[derive(ToSchema)]
#[schema(xml(name = "user", prefix = "u", namespace = "https://user.xml.schema.test"))]
struct User {
#[schema(xml(attribute, prefix = "u"))]
id: i64,
#[schema(xml(name = "user_name", prefix = "u"))]
username: String,
#[schema(xml(wrapped(name = "linkList"), name = "link"))]
links: Vec<String>,
#[schema(xml(wrapped, name = "photo_url"))]
photos_urls: Vec<String>
}
Use of Rust’s own #[deprecated]
attribute will reflect to generated OpenAPI spec.
#[derive(ToSchema)]
#[deprecated]
struct User {
id: i64,
username: String,
links: Vec<String>,
#[deprecated]
photos_urls: Vec<String>
}
Enforce type being used in OpenAPI spec to String
with value_type
and set format to octet stream
with SchemaFormat::KnownFormat(KnownFormat::Binary)
.
#[derive(ToSchema)]
struct Post {
id: i32,
#[schema(value_type = String, format = Binary)]
value: Vec<u8>,
}
Enforce type being used in OpenAPI spec to String
with value_type
option.
#[derive(ToSchema)]
#[schema(value_type = String)]
struct Value(i64);
Override the Bar
reference with a custom::NewBar
reference.
#[derive(ToSchema)]
struct Value {
#[schema(value_type = custom::NewBar)]
field: Bar,
};
Use a virtual Object
type to render generic object
(type: object
) in OpenAPI spec.
#[derive(ToSchema)]
struct Value {
#[schema(value_type = Object)]
field: Bar,
};
Serde rename
/ rename_all
will take precedence over schema rename
/ rename_all
.
#[derive(utoipa::ToSchema, serde::Deserialize)]
#[serde(rename_all = "lowercase")]
#[schema(rename_all = "UPPERCASE")]
enum Random {
#[serde(rename = "string_value")]
#[schema(rename = "custom_value")]
String(String),
Number {
id: i32,
}
}
Add title
to the enum.
#[derive(utoipa::ToSchema)]
#[schema(title = "UserType")]
enum UserType {
Admin,
Moderator,
User,
}
Example with validation attributes.
#[derive(utoipa::ToSchema)]
struct Item {
#[schema(maximum = 10, minimum = 5, multiple_of = 2.5)]
id: i32,
#[schema(max_length = 10, min_length = 5, pattern = "[a-z]*")]
value: String,
#[schema(max_items = 5, min_items = 1)]
items: Vec<String>,
}
Use schema_with
to manually implement schema for a field.
fn custom_type() -> Object {
ObjectBuilder::new()
.schema_type(utoipa::openapi::SchemaType::String)
.format(Some(utoipa::openapi::SchemaFormat::Custom(
"email".to_string(),
)))
.description(Some("this is the description"))
.build()
}
#[derive(utoipa::ToSchema)]
struct Value {
#[schema(schema_with = custom_type)]
id: String,
}
Use as
attribute to change the name and the path of the schema in the generated OpenAPI
spec.
#[derive(utoipa::ToSchema)]
#[schema(as = api::models::person::Person)]
struct Person {
name: String,
}
More examples for value_type
in IntoParams
derive docs.