marshmallow-jsonschema translates marshmallow
schemas into JSON Schema Draft v7 compliant
documents.
A few common reasons:
- Render a marshmallow schema as a form in another runtime (web browser, mobile, native desktop) where you can't import Python.
- Validate request/response bodies in an API gateway or contract-test layer that consumes JSON Schema directly.
- Publish your schema as documentation alongside an OpenAPI spec.
Requires Python 3.9+ and marshmallow 3.13 or later (works on both marshmallow 3 and marshmallow 4).
pip install marshmallow-jsonschema
For older environments:
- marshmallow 2 →
marshmallow-jsonschema<0.11 - Python 3.6–3.8 or marshmallow 3.11–3.12 →
marshmallow-jsonschema<0.14 - A marshmallow-4-broken intermediate state →
marshmallow-jsonschema<0.14(withmarshmallow<4)
- react-jsonschema-form (React; see the extension section below)
- json-editor (vanilla JS; used in
example/example.py)
from marshmallow import Schema, fields
from marshmallow_jsonschema import JSONSchema
class UserSchema(Schema):
username = fields.String()
age = fields.Integer()
birthday = fields.Date()
JSONSchema().dump(UserSchema())Yields:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/UserSchema",
"definitions": {
"UserSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"age": {"title": "age", "type": "integer"},
"birthday": {"title": "birthday", "type": "string", "format": "date"},
"username": {"title": "username", "type": "string"}
}
}
}
}Nested schemas land in definitions and are referenced via $ref:
from marshmallow import Schema, fields
from marshmallow_jsonschema import JSONSchema
class AddressSchema(Schema):
street = fields.String()
city = fields.String()
class UserSchema(Schema):
name = fields.String()
address = fields.Nested(AddressSchema)
JSONSchema().dump(UserSchema())Yields:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/UserSchema",
"definitions": {
"AddressSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"city": {"title": "city", "type": "string"},
"street": {"title": "street", "type": "string"}
}
},
"UserSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"address": {"type": "object", "$ref": "#/definitions/AddressSchema"},
"name": {"title": "name", "type": "string"}
}
}
}
}fields.Nested("Self") and fields.Nested(lambda: SomeSchema()) are
both supported for recursive references.
Passing many=True to a schema describes a list of objects rather
than a single one; the dumped JSON Schema reflects that with an array
envelope:
JSONSchema().dump(UserSchema(many=True))Yields:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {"UserSchema": { ... }},
"type": "array",
"items": {"$ref": "#/definitions/UserSchema"}
}A complete runnable Flask example lives at
example/example.py. It exposes a marshmallow
schema as JSON Schema and renders it as a form using
json-editor — pure JS,
no build pipeline, drop in via CDN:
pip install -r example/requirements.txt
python example/example.py
# open http://127.0.0.1:5000/
For a richer React-based alternative, see
ReactJsonSchemaFormJSONSchema below.
Marshmallow's standard validators translate automatically into JSON Schema constraints when the field is dumped:
| Validator | JSON Schema output |
|---|---|
validate.Length(min=, max=) |
minLength / maxLength for strings, minItems / maxItems for lists & nested |
validate.Range(min=, max=, min_inclusive=, max_inclusive=) |
minimum / maximum (or exclusiveMinimum / exclusiveMaximum) |
validate.OneOf(choices, labels=) |
enum (and the non-standard enumNames for compatibility with react-jsonschema-form) |
validate.Equal(value) |
enum: [value] |
validate.Regexp(pattern) |
pattern |
validate.ContainsOnly(choices, labels=) |
items.anyOf: [{const}, ...] + uniqueItems: true |
from marshmallow import Schema, fields, validate
from marshmallow_jsonschema import JSONSchema
class UserSchema(Schema):
age = fields.Integer(validate=validate.Range(min=0, max=150))
name = fields.String(validate=validate.Length(min=1, max=100))
role = fields.String(validate=validate.OneOf(["admin", "user"]))For a custom validator that's a subclass of one of the above, set
_jsonschema_base_validator_class = validate.<Base> on it so the
translation still fires.
marshmallow.fields.Enum (added in marshmallow 3.18) is supported
out of the box and emits the enum-member names. The third-party
marshmallow-enum
EnumField is also supported when installed; native Enum is preferred
when both are present.
by_value=True enums are supported when every member's value is a
string — the common pattern for serialising enums as their string
value in the wire format:
class Status(str, Enum):
ACTIVE = "active"
INACTIVE = "inactive"
class S(Schema):
status = fields.Enum(Status, by_value=True)
# {"status": {"enum": ["active", "inactive"], "type": "string"}}Mixed-type or non-string enum values still raise
NotImplementedError — use the class MyEnum(str, Enum) pattern, or
load by name instead.
Setting title or description on a schema's inner Meta class
emits them at the corresponding definition entry:
class UserSchema(Schema):
class Meta:
title = "User"
description = "A user account record."
name = fields.String()By default nested schemas live under #/definitions/<Name>. Pass
definitions_path to use a different single-segment key:
JSONSchema(definitions_path="schemas").dump(MySchema())
# {"$ref": "#/schemas/MySchema", "schemas": {...}, ...}Multi-segment paths (e.g. "components/schemas") are rejected because
they would produce a flat dict key with a slash in it rather than the
nested structure consumers expect — wrap the output yourself if you
need that shape.
Add a _jsonschema_type_mapping method to your field so we know how
to serialize it. Field-level metadata={...} and dump_default
values are then merged in automatically, so a single mapping method
gets you the full set of standard schema attributes.
class Colour(fields.Field):
def _jsonschema_type_mapping(self):
return {"type": "string"}
def _serialize(self, value, attr, obj):
r, g, b = value
return "#%02X%02X%02X" % (r, g, b)
class UserSchema(Schema):
favourite_colour = Colour(
dump_default="#ffffff",
metadata={"title": "Colour", "description": "Hex RGB"},
)For wrapper-style custom fields that need to re-enter the dumping
machinery (e.g. to emit a $ref to a recursive schema), declare
_jsonschema_type_mapping(self, json_schema, obj) with the two extra
parameters and the JSONSchema instance + obj will be passed in.
When the optional marshmallow-oneofschema
package is installed, dumping a OneOfSchema produces a JSON Schema
oneOf over each variant — with the discriminator field pinned to its
constant value:
from marshmallow import Schema, fields
from marshmallow_oneofschema import OneOfSchema
from marshmallow_jsonschema import JSONSchema
class TriangleSchema(Schema):
base = fields.Float(required=True)
height = fields.Float(required=True)
class CircleSchema(Schema):
radius = fields.Float(required=True)
class ShapeSchema(OneOfSchema):
type_schemas = {"triangle": TriangleSchema, "circle": CircleSchema}
JSONSchema().dump(ShapeSchema())Yields (abbreviated):
{
"$schema": "http://json-schema.org/draft-07/schema#",
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"base": {"type": "number", "...": "..."},
"height": {"type": "number", "...": "..."},
"type": {"const": "triangle", "type": "string"}
},
"required": ["base", "height", "type"]
},
{ "...circle variant...": "..." }
]
}Variants are inlined (not $ref) so the schema actually validates the
wire format OneOfSchema produces. Custom type_field (default
"type") is honored. Install with pip install marshmallow-jsonschema[oneofschema].
react-jsonschema-form
renders JSON Schema as a React form. It accepts a separate
uiSchema
that controls presentation; this package's
ReactJsonSchemaFormJSONSchema extension dumps both at once:
from marshmallow import Schema, fields
from marshmallow_jsonschema.extensions import ReactJsonSchemaFormJSONSchema
class MySchema(Schema):
first_name = fields.String(metadata={"ui:autofocus": True})
last_name = fields.String()
class Meta:
react_uischema_extra = {"ui:order": ["first_name", "last_name"]}
json_schema_obj = ReactJsonSchemaFormJSONSchema()
data = json_schema_obj.dump(MySchema())
ui_schema_json = json_schema_obj.dump_uischema(MySchema())Bug reports and pull requests are welcome. See CONTRIBUTING.md for local-dev setup and CONTRIBUTORS.md for the people who built this.