NOTE
This is a maintained refactor of the original marshmallow-jsonschema project.
The main goals of this refactor were:
- Fix some long standing bugs
- Support newer versions of Python
- Publish a more recent release
- Modernise builds and tooling to enable active development and future work
marshmallow-jsonschema translates marshmallow schemas into JSON Schema Draft v7 compliant jsonschema. See http://json-schema.org/
What are the use cases for this? Let's say you have a marshmallow schema in python, but you want to render your schema as a form in another system (for example: a web browser or mobile device).
Requires python>=3.10 and marshmallow>=3.11. (For python 2 & marshmallow 2 support, please use marshmallow-jsonschema<0.11)
pip install marshmallow-jsonschema
- react-jsonschema-form (recommended)
- See below extension for this excellent library!
- https://github.com/brutusin/json-forms
- https://github.com/jdorn/json-editor
- https://github.com/ulion/jsonform
from marshmallow import Schema, fields
from marshmallow_jsonschema import JSONSchema
class UserSchema(Schema):
username = fields.String()
age = fields.Integer()
birthday = fields.Date()
user_schema = UserSchema()
json_schema = JSONSchema()
json_schema.dump(user_schema)
Yields:
{'properties': {'age': {'format': 'integer',
'title': 'age',
'type': 'number'},
'birthday': {'format': 'date',
'title': 'birthday',
'type': 'string'},
'username': {'title': 'username', 'type': 'string'}},
'required': [],
'type': 'object'}
from marshmallow import Schema, fields
from marshmallow_jsonschema import JSONSchema
from tests import UserSchema
class Athlete(object):
user_schema = UserSchema()
def __init__(self):
self.name = 'sam'
class AthleteSchema(Schema):
user_schema = fields.Nested(JSONSchema)
name = fields.String()
athlete = Athlete()
athlete_schema = AthleteSchema()
athlete_schema.dump(athlete)
This example renders a form not dissimilar to how wtforms might render a form.
However rather than rendering the form in python, the JSON Schema is rendered using the javascript library brutusin/json-forms.
from flask import Flask, jsonify
from marshmallow import Schema, fields
from marshmallow_jsonschema import JSONSchema
app = Flask(__name__)
class UserSchema(Schema):
name = fields.String()
address = fields.String()
@app.route('/schema')
def schema():
schema = UserSchema()
return jsonify(JSONSchema().dump(schema))
@app.route('/')
def home():
return '''<!DOCTYPE html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/brutusin.json-forms/1.3.0/css/brutusin-json-forms.css"><Paste>
<script src="https://code.jquery.com/jquery-1.12.1.min.js" integrity="sha256-I1nTg78tSrZev3kjvfdM5A5Ak/blglGzlaZANLPDl3I=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.string/3.3.4/underscore.string.min.js"></script>
<script src="https://cdn.jsdelivr.net/brutusin.json-forms/1.3.0/js/brutusin-json-forms.min.js"></script>
<script>
$(document).ready(function() {
$.ajax({
url: '/schema'
, success: function(data) {
var container = document.getElementById('myform');
var BrutusinForms = brutusin["json-forms"];
var bf = BrutusinForms.create(data);
bf.render(container);
}
});
});
</script>
</head>
<body>
<div id="myform"></div>
</body>
</html>
'''
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
For custom field classes, you can add a mapping to an equivalent python type using the 'jsonschema_python_type'
key inside metadata
. This allows the library to attempt to populate schema values as if it were an instance of a Field
with equivalence to that python type.
If requiring proper schema validation and nesting with custom list-like fields, consider subclassing fields.List
, or alternatively provide a self.inner
attribute, set to a field instance representing the type of the items inside the custom list.
Example custom field definitions, using 'jsonschema_python_type'
:
class Colour(fields.Field):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.metadata["jsonschema_python_type"] = str
def _serialize(self, value, _attr, _obj):
r, g, b = value
return f"#{r:x}{g:x}{b:x}"
class ColourList(fields.Field):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.metadata["jsonschema_python_type"] = list
self.inner = Colour()
class FlexibleType(fields.Field):
def __init__(self, **kwargs):
super().__init__(**kwargs)
print(f"This is field treated like a {self.metadata['jsonschema_python_type']}")
class UserSchema(Schema):
favourite_colour = Colour()
close_favourites = ColourList()
bool_field = FlexibleType(metadata={"jsonschema_python_type": bool})
int_field = FlexibleType(metadata={"jsonschema_python_type": int})
schema = UserSchema()
json_schema = JSONSchema()
json_schema.dump(schema)
As an alternative option, you can also supply an equivalent Field
type here instead. For example "{jsonschema_python_type": fields.String}
.
If desiring strict control over the output schema for a custom field, add a _jsonschema_type_mapping
method to your field to supply your own field schema.
Whatever is put here will be exactly what gets serialized to JSON Schema.
Note that no automated nesting logic or validation will be applied for a schema given this way.
A common use case for this is creating a dropdown menu using enum (see Gender below).
class Colour(fields.Field):
def _jsonschema_type_mapping(self):
return {
'type': 'string',
}
def _serialize(self, value, _attr, _obj):
r, g, b = value
return f"#{r:x}{g:x}{b:x}"
class Gender(fields.String):
def _jsonschema_type_mapping(self):
return {
'type': 'string',
'enum': ['Male', 'Female']
}
class UserSchema(Schema):
name = fields.String(required=True)
favourite_colour = Colour()
gender = Gender()
schema = UserSchema()
json_schema = JSONSchema()
json_schema.dump(schema)
An alternative use of the _jsonschema_type_mapping()
method is unlocked by providing the "generate_missing_schema_keys"
key, with an equivalent python type as the value.
This allows the library to attempt to automatically generate the values for missing keys it can extract from the field, given the equivalent type.
_jsonschema_type_mapping()
is deprecated in favour of using'jsonschema_python_type'
for type aliases, as described above.
react-jsonschema-form
is a library for rendering jsonschemas as a form using React. It is very powerful
and full featured.. the catch is that it requires a proprietary
uiSchema
to provide advanced control how the form is rendered.
Here's a live playground
(new in version 0.10.0)
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()
schema = MySchema()
# here's your jsonschema
data = json_schema_obj.dump(schema)
# ..and here's your uiSchema!
ui_schema_json = json_schema_obj.dump_uischema(schema)