Schema
Pydantic allows auto creation of JSON Schemas from models:
from enum import Enum from pydantic import BaseModel, Field class FooBar(BaseModel): count: int size: float = None class Gender(str, Enum): male = 'male' female = 'female' other = 'other' not_given = 'not_given' class MainModel(BaseModel): """ This is the description of the main model """ foo_bar: FooBar = Field(...) gender: Gender = Field(None, alias='Gender') snap: int = Field( 42, title='The Snap', description='this is the value of snap', gt=30, lt=50, ) class Config: title = 'Main' print(MainModel.schema()) # > { # 'type': 'object', # 'title': 'Main', # 'properties': { # 'foo_bar': { # ... print(MainModel.schema_json(indent=2))
(This script is complete, it should run "as is")
Outputs:
{ "title": "Main", "description": "This is the description of the main model", "type": "object", "properties": { "foo_bar": { "$ref": "#/definitions/FooBar" }, "Gender": { "title": "Gender", "enum": [ "male", "female", "other", "not_given" ], "type": "string" }, "snap": { "title": "The Snap", "description": "this is the value of snap", "default": 42, "exclusiveMinimum": 30, "exclusiveMaximum": 50, "type": "integer" } }, "required": [ "foo_bar" ], "definitions": { "FooBar": { "title": "FooBar", "type": "object", "properties": { "count": { "title": "Count", "type": "integer" }, "size": { "title": "Size", "type": "number" } }, "required": [ "count" ] } } }
The generated schemas are compliant with the specifications: JSON Schema Core, JSON Schema Validation and OpenAPI.
BaseModel.schema
will return a dict of the schema, while BaseModel.schema_json
will return a JSON string
representation of that.
Sub-models used are added to the definitions
JSON attribute and referenced, as per the spec.
All sub-models (and their sub-models) schemas are put directly in a top-level definitions
JSON key for easy re-use
and reference.
"sub-models" with modifications (via the Field
class) like a custom title, description or default value,
are recursively included instead of referenced.
The description
for models is taken from the docstring of the class or the argument description
to
the Field
class.
Field customisation🔗
Optionally the Field
function can be used to provide extra information about the field and validations, arguments:
default
(positional argument), since theField
is replacing the field's default, its first argument is used to set the default, use ellipsis (...
) to indicate the field is requiredalias
- the public name of the fieldtitle
if omittedfield_name.title()
is useddescription
if omitted and the annotation is a sub-model, the docstring of the sub-model will be usedconst
this field must take it's default value if it is presentgt
for numeric values (int
,float
,Decimal
), adds a validation of "greater than" and an annotation ofexclusiveMinimum
to the JSON Schemage
for numeric values, adds a validation of "greater than or equal" and an annotation ofminimum
to the JSON Schemalt
for numeric values, adds a validation of "less than" and an annotation ofexclusiveMaximum
to the JSON Schemale
for numeric values, adds a validation of "less than or equal" and an annotation ofmaximum
to the JSON Schemamultiple_of
for numeric values, adds a validation of "a multiple of" and an annotation ofmultipleOf
to the JSON Schemamin_items
for list values, adds a corresponding validation and an annotation ofminItems
to the JSON Schemamax_items
for list values, adds a corresponding validation and an annotation ofmaxItems
to the JSON Schemamin_length
for string values, adds a corresponding validation and an annotation ofminLength
to the JSON Schemamax_length
for string values, adds a corresponding validation and an annotation ofmaxLength
to the JSON Schemaregex
for string values, adds a Regular Expression validation generated from the passed string and an annotation ofpattern
to the JSON Schema**
any other keyword arguments (eg.examples
) will be added verbatim to the field's schema
Instead of using Field
, the fields
property of the Config class can be used
to set all the arguments above except default
.
The schema is generated by default using aliases as keys, it can also be generated using model
property names not aliases with MainModel.schema/schema_json(by_alias=False)
.
JSON Schema Types🔗
Types, custom field types, and constraints (as max_length
) are mapped to the corresponding
JSON Schema Core spec format when there's
an equivalent available, next to JSON Schema Validation,
OpenAPI Data Types
(which are based on JSON Schema), or otherwise use the standard format
JSON field to define Pydantic extensions
for more complex string
sub-types.
The field schema mapping from Python / Pydantic to JSON Schema is done as follows:
Python type | JSON Schema Type | Additional JSON Schema | Defined in |
---|---|---|---|
bool
|
boolean
|
JSON Schema Core | |
str
|
string
|
JSON Schema Core | |
float
|
number
|
JSON Schema Core | |
int
|
integer
|
JSON Schema Validation | |
dict
|
object
|
JSON Schema Core | |
list
|
array
|
{"items": {}}
|
JSON Schema Core |
tuple
|
array
|
{"items": {}}
|
JSON Schema Core |
set
|
array
|
{"items": {}, {"uniqueItems": true}
|
JSON Schema Validation |
List[str]
|
array
|
{"items": {"type": "string"}}
|
JSON Schema Validation |
And equivalently for any other sub type, e.g. List[int] .
|
|||
Tuple[str, int]
|
array
|
{"items": [{"type": "string"}, {"type": "integer"}]}
|
JSON Schema Validation |
And equivalently for any other set of subtypes. Note: If using schemas for OpenAPI, you shouldn't use this declaration, as it would not be valid in OpenAPI (although it is valid in JSON Schema). | |||
Dict[str, int]
|
object
|
{"additionalProperties": {"type": "integer"}}
|
JSON Schema Validation |
And equivalently for any other subfields for dicts. Have in mind that although you can use other types as keys for dicts with Pydantic, only strings are valid keys for JSON, and so, only str is valid as JSON Schema key types. | |||
Union[str, int]
|
anyOf
|
{"anyOf": [{"type": "string"}, {"type": "integer"}]}
|
JSON Schema Validation |
And equivalently for any other subfields for unions. | |||
Enum
|
enum
|
{"enum": [...]}
|
JSON Schema Validation |
All the literal values in the enum are included in the definition. | |||
SecretStr
|
string
|
{"writeOnly": true}
|
JSON Schema Validation |
SecretBytes
|
string
|
{"writeOnly": true}
|
JSON Schema Validation |
EmailStr
|
string
|
{"format": "email"}
|
JSON Schema Validation |
NameEmail
|
string
|
{"format": "name-email"}
|
Pydantic standard "format" extension |
AnyUrl
|
string
|
{"format": "uri"}
|
JSON Schema Validation |
DSN
|
string
|
{"format": "dsn"}
|
Pydantic standard "format" extension |
bytes
|
string
|
{"format": "binary"}
|
OpenAPI |
Decimal
|
number
|
JSON Schema Core | |
UUID1
|
string
|
{"format": "uuid1"}
|
Pydantic standard "format" extension |
UUID3
|
string
|
{"format": "uuid3"}
|
Pydantic standard "format" extension |
UUID4
|
string
|
{"format": "uuid4"}
|
Pydantic standard "format" extension |
UUID5
|
string
|
{"format": "uuid5"}
|
Pydantic standard "format" extension |
UUID
|
string
|
{"format": "uuid"}
|
Pydantic standard "format" extension |
Suggested in OpenAPI. | |||
FilePath
|
string
|
{"format": "file-path"}
|
Pydantic standard "format" extension |
DirectoryPath
|
string
|
{"format": "directory-path"}
|
Pydantic standard "format" extension |
Path
|
string
|
{"format": "path"}
|
Pydantic standard "format" extension |
datetime
|
string
|
{"format": "date-time"}
|
JSON Schema Validation |
date
|
string
|
{"format": "date"}
|
JSON Schema Validation |
time
|
string
|
{"format": "time"}
|
JSON Schema Validation |
timedelta
|
number
|
{"format": "time-delta"}
|
Difference in seconds (a float ), with Pydantic standard "format" extension
|
Suggested in JSON Schema repository's issues by maintainer. | |||
Json
|
string
|
{"format": "json-string"}
|
Pydantic standard "format" extension |
IPv4Address
|
string
|
{"format": "ipv4"}
|
JSON Schema Validation |
IPv6Address
|
string
|
{"format": "ipv6"}
|
JSON Schema Validation |
IPvAnyAddress
|
string
|
{"format": "ipvanyaddress"}
|
Pydantic standard "format" extension |
IPv4 or IPv6 address as used in ipaddress module
|
|||
IPv4Interface
|
string
|
{"format": "ipv4interface"}
|
Pydantic standard "format" extension |
IPv4 interface as used in ipaddress module
|
|||
IPv6Interface
|
string
|
{"format": "ipv6interface"}
|
Pydantic standard "format" extension |
IPv6 interface as used in ipaddress module
|
|||
IPvAnyInterface
|
string
|
{"format": "ipvanyinterface"}
|
Pydantic standard "format" extension |
IPv4 or IPv6 interface as used in ipaddress module
|
|||
IPv4Network
|
string
|
{"format": "ipv4network"}
|
Pydantic standard "format" extension |
IPv4 network as used in ipaddress module
|
|||
IPv6Network
|
string
|
{"format": "ipv6network"}
|
Pydantic standard "format" extension |
IPv6 network as used in ipaddress module
|
|||
IPvAnyNetwork
|
string
|
{"format": "ipvanynetwork"}
|
Pydantic standard "format" extension |
IPv4 or IPv6 network as used in ipaddress module
|
|||
StrictBool
|
boolean
|
JSON Schema Core | |
StrictStr
|
string
|
JSON Schema Core | |
ConstrainedStr
|
string
|
JSON Schema Core | |
If the type has values declared for the constraints, they are included as validations. See the mapping for constr below.
|
|||
constr(regex='^text$', min_length=2, max_length=10)
|
string
|
{"pattern": "^text$", "minLength": 2, "maxLength": 10}
|
JSON Schema Validation |
Any argument not passed to the function (not defined) will not be included in the schema. | |||
ConstrainedInt
|
integer
|
JSON Schema Core | |
If the type has values declared for the constraints, they are included as validations. See the mapping for conint below.
|
|||
conint(gt=1, ge=2, lt=6, le=5, multiple_of=2)
|
integer
|
{"maximum": 5, "exclusiveMaximum": 6, "minimum": 2, "exclusiveMinimum": 1, "multipleOf": 2}
|
|
Any argument not passed to the function (not defined) will not be included in the schema. | |||
PositiveInt
|
integer
|
{"exclusiveMinimum": 0}
|
JSON Schema Validation |
NegativeInt
|
integer
|
{"exclusiveMaximum": 0}
|
JSON Schema Validation |
ConstrainedFloat
|
number
|
JSON Schema Core | |
If the type has values declared for the constraints, they are included as validations. See the mapping for confloat below.
|
|||
confloat(gt=1, ge=2, lt=6, le=5, multiple_of=2)
|
number
|
{"maximum": 5, "exclusiveMaximum": 6, "minimum": 2, "exclusiveMinimum": 1, "multipleOf": 2}
|
JSON Schema Validation |
Any argument not passed to the function (not defined) will not be included in the schema. | |||
PositiveFloat
|
number
|
{"exclusiveMinimum": 0}
|
JSON Schema Validation |
NegativeFloat
|
number
|
{"exclusiveMaximum": 0}
|
JSON Schema Validation |
ConstrainedDecimal
|
number
|
JSON Schema Core | |
If the type has values declared for the constraints, they are included as validations. See the mapping for condecimal below.
|
|||
condecimal(gt=1, ge=2, lt=6, le=5, multiple_of=2)
|
number
|
{"maximum": 5, "exclusiveMaximum": 6, "minimum": 2, "exclusiveMinimum": 1, "multipleOf": 2}
|
JSON Schema Validation |
Any argument not passed to the function (not defined) will not be included in the schema. | |||
BaseModel
|
object
|
JSON Schema Core | |
All the properties defined will be defined with standard JSON Schema, including submodels. | |||
Color
|
string
|
{"format": "color"}
|
Pydantic standard "format" extension |
Top-level schema generation🔗
You can also generate a top-level JSON Schema that only includes a list of models and all their related
submodules in its definitions
:
import json from pydantic import BaseModel from pydantic.schema import schema class Foo(BaseModel): a: str = None class Model(BaseModel): b: Foo class Bar(BaseModel): c: int top_level_schema = schema([Model, Bar], title='My Schema') print(json.dumps(top_level_schema, indent=2)) # { # "title": "My Schema", # "definitions": { # "Foo": { # "title": "Foo", # ...
(This script is complete, it should run "as is")
Outputs:
{ "title": "My Schema", "definitions": { "Foo": { "title": "Foo", "type": "object", "properties": { "a": { "title": "A", "type": "string" } } }, "Model": { "title": "Model", "type": "object", "properties": { "b": { "$ref": "#/definitions/Foo" } }, "required": [ "b" ] }, "Bar": { "title": "Bar", "type": "object", "properties": { "c": { "title": "C", "type": "integer" } }, "required": [ "c" ] } } }
Schema customization🔗
You can customize the generated $ref
JSON location, the definitions will still be in the key definitions
and
you can still get them from there, but the references will point to your defined prefix instead of the default.
This is useful if you need to extend or modify JSON Schema default definitions location, e.g. with OpenAPI:
import json from pydantic import BaseModel from pydantic.schema import schema class Foo(BaseModel): a: int class Model(BaseModel): a: Foo top_level_schema = schema([Model], ref_prefix='#/components/schemas/') # Default location for OpenAPI print(json.dumps(top_level_schema, indent=2)) # { # "definitions": { # "Foo": { # "title": "Foo", # "type": "object", # ...
(This script is complete, it should run "as is")
Outputs:
{ "definitions": { "Foo": { "title": "Foo", "type": "object", "properties": { "a": { "title": "A", "type": "integer" } }, "required": [ "a" ] }, "Model": { "title": "Model", "type": "object", "properties": { "a": { "$ref": "#/components/schemas/Foo" } }, "required": [ "a" ] } } }
It's also possible to extend/override the generated JSON schema in a model.
To do it, use the Config
sub-class attribute schema_extra
.
For example, you could add examples
to the JSON Schema:
from pydantic import BaseModel class Person(BaseModel): name: str age: int class Config: schema_extra = { 'examples': [ { 'name': 'John Doe', 'age': 25, } ] } print(Person.schema()) # {'title': 'Person', # 'type': 'object', # 'properties': {'name': {'title': 'Name', 'type': 'string'}, # 'age': {'title': 'Age', 'type': 'integer'}}, # 'required': ['name', 'age'], # 'examples': [{'name': 'John Doe', 'age': 25}]} print(Person.schema_json(indent=2))
(This script is complete, it should run "as is")
Outputs:
{ "title": "Person", "type": "object", "properties": { "name": { "title": "Name", "type": "string" }, "age": { "title": "Age", "type": "integer" } }, "required": [ "name", "age" ], "examples": [ { "name": "John Doe", "age": 25 } ]