A Django REST framework API adapter for the JSON:API spec.
—
JSON:API renderers convert Django REST framework responses to JSON:API format, while parsers handle incoming JSON:API requests. These components ensure proper resource object structure, relationship handling, meta information, and error formatting.
Main JSON:API renderer that transforms Django REST framework responses into JSON:API compliant format.
class JSONRenderer(renderers.JSONRenderer):
"""
JSON:API compliant renderer with media type application/vnd.api+json.
Transforms Django REST framework responses into JSON:API format with:
- Resource objects with type, id, attributes, and relationships
- Top-level data, meta, and links sections
- Proper error formatting
- Include parameter support for compound documents
"""
media_type = "application/vnd.api+json"
format = "vnd.api+json"
@classmethod
def extract_attributes(cls, fields, resource):
"""
Extract attributes from resource data for JSON:API resource object.
Args:
fields: Serializer fields dict
resource: Resource data dict
Returns:
dict: Attributes dict with formatted field names
"""
@classmethod
def extract_relationships(cls, fields, resource, resource_instance):
"""
Extract relationships from resource data for JSON:API resource object.
Args:
fields: Serializer fields dict
resource: Resource data dict
resource_instance: Django model instance
Returns:
dict: Relationships dict with data and links
"""
def render(self, data, accepted_media_type=None, renderer_context=None):
"""
Render data as JSON:API response.
Args:
data: Data to render
accepted_media_type: Accepted media type
renderer_context: Request context
Returns:
bytes: JSON:API formatted response
"""Usage example:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework_json_api.renderers.JSONRenderer',
],
}
# Transforms this Django REST framework response:
# {"id": 1, "title": "Article", "author": 5}
# Into this JSON:API response:
# {
# "data": {
# "type": "articles",
# "id": "1",
# "attributes": {
# "title": "Article"
# },
# "relationships": {
# "author": {
# "data": {"type": "authors", "id": "5"}
# }
# }
# }
# }JSON:API parser that converts incoming JSON:API requests into Django REST framework format.
class JSONParser(parsers.JSONParser):
"""
JSON:API compliant parser with media type application/vnd.api+json.
Parses JSON:API requests and extracts:
- Attributes from resource objects
- Relationships as resource identifier objects
- Meta information
"""
media_type = "application/vnd.api+json"
renderer_class = JSONRenderer
@staticmethod
def parse_attributes(data):
"""
Parse attributes from JSON:API resource object.
Args:
data: JSON:API resource object data
Returns:
dict: Attributes with field names converted to Django format
"""
@staticmethod
def parse_relationships(data):
"""
Parse relationships from JSON:API resource object.
Args:
data: JSON:API resource object data
Returns:
dict: Relationships as resource identifier objects
"""
@staticmethod
def parse_metadata(result):
"""
Parse meta section from JSON:API request.
Args:
result: Full JSON:API request data
Returns:
dict: Meta information with _meta key
"""
def parse_data(self, result, parser_context):
"""
Parse JSON:API request data into Django REST framework format.
Args:
result: Parsed JSON data
parser_context: Parser context with view information
Returns:
dict: Data in Django REST framework format
Raises:
ParseError: If request doesn't contain primary data or is malformed
"""Usage example:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework_json_api.parsers.JSONParser',
],
}
# Parses this JSON:API request:
# {
# "data": {
# "type": "articles",
# "attributes": {
# "title": "New Article",
# "content": "Article content"
# },
# "relationships": {
# "author": {
# "data": {"type": "authors", "id": "5"}
# }
# }
# }
# }
# Into this Django REST framework format:
# {
# "title": "New Article",
# "content": "Article content",
# "author": {"type": "authors", "id": "5"}
# }The JSONRenderer creates responses with this structure:
{
"data": {
"type": "resource-type",
"id": "123",
"attributes": {
"field-name": "value"
},
"relationships": {
"related-field": {
"data": {"type": "related-type", "id": "456"}
}
},
"links": {
"self": "/api/resource-type/123"
}
},
"meta": {
"key": "value"
}
}{
"data": [
{
"type": "resource-type",
"id": "123",
"attributes": {...},
"relationships": {...}
}
],
"meta": {
"pagination": {
"page": 1,
"pages": 10,
"count": 100
}
},
"links": {
"first": "/api/resource-type?page=1",
"next": "/api/resource-type?page=2",
"last": "/api/resource-type?page=10"
}
}{
"errors": [
{
"status": "400",
"detail": "This field is required.",
"source": {
"pointer": "/data/attributes/title"
}
}
]
}Both renderer and parser respect field name formatting settings:
# settings.py
JSON_API_FORMAT_FIELD_NAMES = True
# Django field: created_at
# JSON:API attribute: "created-at"
# Parser automatically converts back:
# JSON:API "created-at" -> Django "created_at"The renderer supports compound documents via the include parameter:
# Request: GET /articles/1?include=author,comments.user
# Response includes related resources in "included" section:
{
"data": {...},
"included": [
{
"type": "authors",
"id": "5",
"attributes": {...}
},
{
"type": "comments",
"id": "10",
"attributes": {...},
"relationships": {
"user": {"data": {"type": "users", "id": "3"}}
}
}
]
}The parser handles relationship endpoint requests:
# POST /articles/1/relationships/author
# {
# "data": {"type": "authors", "id": "6"}
# }
# Parser extracts relationship data for relationship viewsfrom rest_framework_json_api.renderers import JSONRenderer
from rest_framework_json_api.parsers import JSONParser
# Base classes from Django REST framework
from rest_framework.renderers import JSONRenderer as DRFJSONRenderer
from rest_framework.parsers import JSONParser as DRFJSONParserInstall with Tessl CLI
npx tessl i tessl/pypi-djangorestframework-jsonapi