#[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 defineXmlobject 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_allattribute. Will rename all fields of the structs accordingly. If both serderename_alland schemarename_allare 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.defaultCan be used to populate default values on all fields using the struct’sDefaultimplementation.deprecatedCan 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_allattribute. Will rename all variants of the enum accordingly. If both serderename_alland schemarename_allare 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.deprecatedCan 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’sDefaultimplementation.format = ...May either be variant of theKnownFormatenum, 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 notToSchemas norprimitivetypes. The value can be any Rust type what normally could be used to serialize to JSON or either virtual typeObjectorValue, or an alias defined using#[aliases(..)].Objectwill be rendered as generic OpenAPI object (type: object).Valuewill be rendered as any OpenAPI value (i.e. notyperestriction).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.deprecatedCan 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 theKnownFormatenum, or otherwise an open value as a string. By default the format is derived from the type of the property according OpenApi spec.write_onlyDefines property is only used in write operations POST,PUT,PATCH but not in GETread_onlyDefines property is only used in read operations GET but not in POST,PUT,PATCHxml(...)Can be used to defineXmlobject properties applicable to named fields. See configuration options at xml attributes ofToSchemavalue_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 notToSchemas norprimitivetypes. The value can be any Rust type what normally could be used to serialize to JSON, or either virtual typeObjectorValue, or an alias defined using#[aliases(..)].Objectwill be rendered as generic OpenAPI object (type: object).Valuewill be rendered as any OpenAPI value (i.e. notyperestriction).inlineIf 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 rulesnullableDefines property is nullable (note this is different to non-required).rename = ...Supports same syntax as serderenameattribute. Will rename field accordingly. If both serderenameand schemarenameare 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 anumbervalue.minimum = ...Can be used to define inclusive lower bound to anumbervalue.exclusive_maximum = ...Can be used to define exclusive upper bound to anumbervalue.exclusive_minimum = ...Can be used to define exclusive lower bound to anumbervalue.max_length = ...Can be used to define maximum length forstringtypes.min_length = ...Can be used to define minimum length forstringtypes.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 forarrayfields. Value must be non-negative integer.min_items = ...Can be used to define minimum items allowed forarrayfields. Value must be non-negative integer.schema_with = ...Useschemacreated 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 asHashMapandBTreeMap. Free form type enables use of arbitrary types within map values. Supports formatsadditional_propertiesandadditional_properties = true.deprecatedCan 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
Optionfield - and it does not have
skip_serializing_ifproperty - and it does not have
serde_withdouble_option - and it does not have default value provided with serde
defaultattribute
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.tagattribute works as a discriminator field for an enum.content = "..."Supported at the container level, allows adjacently-tagged enums. This attribute requires that atagis present, otherwise serde will trigger a compile-time failure.untaggedSupported at the container level. Allows untagged enum representation.defaultSupported at the container level and field level according to serde attributes.flattenSupported 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.