Skip to main content

JSON Schema Draft v7 (http://json-schema.org/) formatting with marshmallow

Project description

marshmallow-jsonschema: JSON Schema formatting with marshmallow

Build Status Code style: black

marshmallow-jsonschema translates marshmallow schemas into JSON Schema Draft v7 compliant documents.

Why would I want my schema translated to JSON?

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.

Installation

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 (with marshmallow<4)

Client tools that render forms from JSON Schema

Examples

Simple example

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 example

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.

Top-level array (many=True)

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"}
}

Flask + JSON Schema form rendering

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.

Validators

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.

Enums

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.

Advanced usage

Schema-level title and description

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()

Customizing the definitions path

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.

Custom field types

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.

Polymorphic schemas (marshmallow-oneofschema)

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 Extension

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())

Contributing

Bug reports and pull requests are welcome. See CONTRIBUTING.md for local-dev setup and CONTRIBUTORS.md for the people who built this.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

marshmallow_jsonschema-0.16.0.tar.gz (45.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

marshmallow_jsonschema-0.16.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file marshmallow_jsonschema-0.16.0.tar.gz.

File metadata

  • Download URL: marshmallow_jsonschema-0.16.0.tar.gz
  • Upload date:
  • Size: 45.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.16

File hashes

Hashes for marshmallow_jsonschema-0.16.0.tar.gz
Algorithm Hash digest
SHA256 d504ab6156a272d9be850469b2fc4ab3f6e858c3cb66791724afa890dfdee5c8
MD5 c9588520bc9b1ac3fc29c0bfd1ed05a9
BLAKE2b-256 66a41b0fa2a1658b0b797a60ccbd53c7daa5a37d651016f4aa3e451e9c2955fa

See more details on using hashes here.

File details

Details for the file marshmallow_jsonschema-0.16.0-py3-none-any.whl.

File metadata

File hashes

Hashes for marshmallow_jsonschema-0.16.0-py3-none-any.whl
Algorithm Hash digest
SHA256 393b3fd8d73d1d9287c3f65784876c8c14fd41c2553c59a1ea5817d606078105
MD5 23d57ed0c455f672570522dd6df6d6b3
BLAKE2b-256 5ddfe75161abd2fd6624cf280bd2e684104c71b6d4efcc31c80d1286296534b3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page