Quickstart

Note

The following guide assumes some familiarity with the marshmallow API. To learn more about marshmallow, see its official documentation at https://marshmallow.readthedocs.io.

Declaring schemas

Declare your schemas as you would with marshmallow.

A Schema MUST define:

  • An id field
  • The type_ class Meta option

It is RECOMMENDED to set strict mode to True.

Automatic self-linking is supported through these Meta options:

  • self_url specifies the URL to the resource itself
  • self_url_kwargs specifies replacement fields for self_url
  • self_url_many specifies the URL the resource when a collection (many) are serialized
from marshmallow_jsonapi import Schema, fields

class ArticleSchema(Schema):
    id = fields.Str(dump_only=True)
    title = fields.Str()

    class Meta:
        type_ = 'articles'
        self_url = '/articles/{id}'
        self_url_kwargs = {'id': '<id>'}
        self_url_many = '/articles/'
        strict = True

These URLs can be auto-generated by specifying self_view, self_view_kwargs and self_view_many instead when using the Flask integration.

Serialization

Objects will be serialized to JSON API documents with primary data.

ArticleSchema().dump(article).data
# {
#     'data': {
#         'id': '1',
#         'type': 'articles',
#         'attributes': {'title': 'Django is Omakase'}
#     }
# }

Relationships

The Relationship field is used to serialize relationship objects.

To serialize links, pass a URL format string and a dictionary of keyword arguments. String arguments enclosed in < > will be interpreted as attributes to pull from the object being serialized. The relationship links can automatically be generated from Flask view names when using the Flask integration.

class ArticleSchema(Schema):
    id = fields.Str(dump_only=True)
    title = fields.Str()

    author = fields.Relationship(
        self_url='/articles/{article_id}/relationships/author',
        self_url_kwargs={'article_id': '<id>'},
        related_url='/authors/{author_id}',
        related_url_kwargs={'author_id': '<author.id>'}
    )

    class Meta:
        type_ = 'articles'
        strict = True

ArticleSchema().dump(article).data
# {
#     'data': {
#         'id': '1',
#         'type': 'articles'
#         'attributes': {'title': 'Django is Omakase'},
#         'relationships': {
#             'author': {
#                 'links': {
#                     'self': '/articles/1/relationships/author'
#                     'related': '/authors/9',
#                 }
#             }
#         }
#     }
# }

Resource linkages

You can serialize resource linkages by passing include_resource_linkage=True .

class ArticleSchema(Schema):
    id = fields.Str(dump_only=True)
    title = fields.Str()

    comments = fields.Relationship(
        related_url='/posts/{post_id}/comments',
        related_url_kwargs={'post_id': '<id>'},
        # Include resource linkage
        many=True, include_resource_linkage=True,
        type_='comments'
    )
    class Meta:
        type_ = 'articles'
        strict = True

ArticleSchema().dump(article).data
# {
#     "data": {
#         'id': '1',
#         'type': 'articles'
#         'attributes': {'title': 'Django is Omakase'},
#         "relationships": {
#             "comments": {
#                 "links": {
#                     "related": "/posts/1/comments/"
#                 }
#                 "data": [
#                     {"id": "5", "type": "comments"},
#                     {"id": "12", "type": "comments"}
#                 ],
#             }
#         },
#     }
# }

Compound documents

Compound documents allow to include related resources into the request with the primary resource. In order to include objects, you have to define a Schema for the respective relationship, which will be used to render those objects.

class ArticleSchema(Schema):
    id = fields.Str(dump_only=True)
    title = fields.Str()

    comments = fields.Relationship(
        related_url='/posts/{post_id}/comments',
        related_url_kwargs={'post_id': '<id>'},
        many=True, include_resource_linkage=True,
        type_='comments',
        # define a schema for rendering included data
        schema='CommentSchema'
    )
    class Meta:
        type_ = 'articles'
        strict = True

Just as with nested fields the schema can be a class or a string with a simple or fully qualified class name. Make sure to import the schema beforehand.

Now you can include some data in a dump by specifying the includes (also supports nested relations via the dot syntax).

ArticleSchema(include_data=('comments', 'comments.author')).dump(article).data
# {
#     "data": {
#         "id": "1",
#         "type": "articles"
#         "attributes": {"title": "Django is Omakase"},
#         "relationships": {
#             "comments": {
#                 "links": {
#                     "related": "/posts/1/comments/"
#                 }
#                 "data": [
#                     {"id": "5", "type": "comments"},
#                     {"id": "12", "type": "comments"}
#                 ],
#             }
#         },
#     }
#     "included": [
#         {
#             "attributes": {
#                 "body": "Marshmallow is sweet like sugar!"
#             },
#             "id": "17",
#             "links": {"self": "/comments/17/"},
#             "type": "comments"
#         },
#         {
#             "attributes": {
#                 "name": "Laura"
#             },
#             "id": "94",
#             "links": {"self": "/people/94/"},
#             "type": "people"
#         }
#     ]
# }

Meta Objects

The marshmallow_jsonapi.fields.Meta field is used to serialize the meta object within a resource object.

from marshmallow_jsonapi import Schema, fields

class AuthorSchema(Schema):
    id = fields.Str(dump_only=True)
    name = fields.Str()
    metadata = fields.Meta()

    class Meta:
        type_ = 'people'
        strict = True

author = {'name': 'Alice', 'metadata': {'page': {'offset': 10}}}
AuthorSchema().dump(author).data
# {
#     "data": {
#         "id": "1",
#         "type": "people"
#         "attributes": {"name": "Alice"},
#         "meta": {"page": {"offset": 10}}
#     }
# }

Errors

Schema.load and Schema.validate will return JSON API-formatted Error objects.

from pprint import pprint

from marshmallow_jsonapi import Schema, fields
from marshmallow import validate, ValidationError


class AuthorSchema(Schema):
    id = fields.Str(dump_only=True)
    first_name = fields.Str(required=True)
    last_name = fields.Str(required=True)
    password = fields.Str(load_only=True, validate=validate.Length(6))
    twitter = fields.Str()

    class Meta:
        type_ = 'people'
        strict = True

schema = AuthorSchema()
input_data = {
    'data': {
        'type': 'people',
        'attributes': {
            'first_name': 'Dan',
            'password': 'short'
        }
    }
}

try:
    schema.validate(input_data)
except ValidationError as err:
    pprint(err.messages)
# {'errors': [{'detail': 'Shorter than minimum length 6.',
#              'source': {'pointer': '/data/attributes/password'}},
#             {'detail': 'Missing data for required field.',
#              'source': {'pointer': '/data/attributes/last_name'}}]}

Validating type

If an invalid “type” is passed in the input data, an IncorrectTypeError is raised.

from marshmallow_jsonapi.exceptions import IncorrectTypeError

input_data = {
    'data': {
        'type': 'invalid-type',
        'attributes': {
            'first_name': 'Dan',
            'last_name': 'Gebhardt',
            'password': 'verysecure'
        }
    }
}
try:
    schema.validate(input_data)
except IncorrectTypeError as err:
    pprint(err.messages)
# {'errors': [{'detail': 'Invalid type. Expected "people".',
#              'pointer': '/data/type'}]}

Inflection

You can optionally specify a function to transform attribute names. For example, you may decide to follow JSON API’s recommendation to use “dasherized” names.

from marshmallow_jsonapi import Schema, fields

def dasherize(text):
    return text.replace('_', '-')

class AuthorSchema(Schema):
    id = fields.Str(dump_only=True)
    first_name = fields.Str(required=True)
    last_name = fields.Str(required=True)

    class Meta:
        type_ = 'people'
        inflect = dasherize

result = AuthorSchema().dump(author)
result.data
# {
#     'data': {
#         'id': '9',
#         'type': 'people',
#         'attributes': {
#             'first-name': 'Dan',
#             'last-name': 'Gebhardt'
#         }
#     }
# }

Flask integration

marshmallow-jsonapi includes optional utilities to integrate with Flask.

A Flask-specific schema in marshmallow_jsonapi.flask can be used to auto-generate self-links based on view names instead of hard-coding URLs.

Additionally, the Relationship field in the marshmallow_jsonapi.flask module allows you to pass view names instead of path templates to generate relationship links.

from marshmallow_jsonapi import fields
from marshmallow_jsonapi.flask import Relationship, Schema

class ArticleSchema(Schema):
    id = fields.Str(dump_only=True)
    title = fields.Str()

    author = fields.Relationship(
        self_view='article_author',
        self_url_kwargs={'article_id': '<id>'},
        related_view='author_detail',
        related_view_kwargs={'author_id': '<author.id>'}
    )

    comments = Relationship(
        related_view='article_comments',
        related_view_kwargs={'article_id': '<id>'},
        many=True, include_resource_linkage=True,
        type_='comments'
    )

    class Meta:
        type_ = 'posts'
        self_view = 'post_detail'
        self_view_kwargs = {'post_detail': '<id>'}
        self_view_many = 'posts_list'

See here for a full example.