CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework-jsonapi

A Django REST framework API adapter for the JSON:API spec.

Pending
Overview
Eval results
Files

exceptions-utilities.mddocs/

Exception Handling and Utilities

JSON:API compliant error formatting, field name formatting utilities, resource type management, and settings configuration for customizing JSON:API behavior.

Capabilities

Exception Handling

exception_handler

Main exception handler that converts Django REST framework errors to JSON:API format.

def exception_handler(exc, context):
    """
    JSON:API compliant exception handler.
    
    Converts Django REST framework exceptions to JSON:API error format
    with proper error objects containing status, detail, and source information.
    
    Args:
        exc: Exception instance
        context: Exception context with view and request information
        
    Returns:
        Response: JSON:API formatted error response or None
    """

Usage example:

# settings.py
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
}

# Validation errors become:
# {
#   "errors": [{
#     "status": "400",
#     "detail": "This field is required.",
#     "source": {"pointer": "/data/attributes/title"}
#   }]
# }

# Permission errors become:
# {
#   "errors": [{
#     "status": "403", 
#     "detail": "You do not have permission to perform this action."
#   }]
# }

rendered_with_json_api

Utility function to check if a view uses JSON:API renderer.

def rendered_with_json_api(view):
    """
    Check if view is rendered with JSON:API renderer.
    
    Args:
        view: View instance
        
    Returns:
        bool: True if view uses JSONRenderer
    """

Conflict

HTTP 409 Conflict exception for JSON:API responses.

class Conflict(exceptions.APIException):
    """
    HTTP 409 Conflict exception.
    
    Used for resource conflicts in JSON:API applications.
    """
    
    status_code = 409
    default_detail = "Conflict."

Usage example:

from rest_framework_json_api.exceptions import Conflict

def update_article(self, instance, validated_data):
    if instance.locked:
        raise Conflict("Article is locked and cannot be modified.")
    return super().update(instance, validated_data)

Utilities

Resource Name and Type Management

def get_resource_name(context, expand_polymorphic_types=False):
    """
    Get resource name from view context.
    
    Args:
        context: Serializer context with view and request
        expand_polymorphic_types: Whether to expand polymorphic types
        
    Returns:
        str or list: Resource name or list of polymorphic types
    """

def get_resource_type_from_model(model):
    """
    Get resource type from Django model.
    
    Args:
        model: Django model class
        
    Returns:
        str: Resource type name
    """

def get_resource_type_from_serializer(serializer):
    """
    Get resource type from serializer.
    
    Args:
        serializer: Serializer instance or class
        
    Returns:
        str: Resource type name
    """

def get_resource_type_from_instance(instance):
    """
    Get resource type from model instance.
    
    Args:
        instance: Django model instance
        
    Returns:
        str: Resource type name
    """

def get_resource_type_from_queryset(queryset):
    """
    Get resource type from QuerySet.
    
    Args:
        queryset: Django QuerySet
        
    Returns:
        str: Resource type name
    """

Field Name Formatting

def format_field_names(obj, format_type=None):
    """
    Format all field names in an object.
    
    Args:
        obj: Dict or object with field names to format
        format_type: Format type override
        
    Returns:
        dict: Object with formatted field names
    """

def format_field_name(value, format_type=None):
    """
    Format a single field name.
    
    Args:
        value: Field name to format
        format_type: Format type override
        
    Returns:
        str: Formatted field name
    """

def undo_format_field_names(obj):
    """
    Reverse field name formatting.
    
    Args:
        obj: Dict with formatted field names
        
    Returns:
        dict: Object with original field names
    """

def undo_format_field_name(value):
    """
    Reverse format a single field name.
    
    Args:
        value: Formatted field name
        
    Returns:
        str: Original field name
    """

Usage example:

# With JSON_API_FORMAT_FIELD_NAMES = True
format_field_name('created_at')     # Returns 'created-at'
format_field_name('author_name')    # Returns 'author-name'

undo_format_field_name('created-at')   # Returns 'created_at'
undo_format_field_name('author-name')  # Returns 'author_name'

Resource and Serializer Utilities

def get_serializer_fields(serializer):
    """
    Get fields from serializer, handling both regular and list serializers.
    
    Args:
        serializer: Serializer instance
        
    Returns:
        dict or None: Serializer fields
    """

def get_included_resources(request, serializer_class):
    """
    Parse include parameter from request.
    
    Args:
        request: HTTP request object
        serializer_class: Serializer class
        
    Returns:
        list: List of include paths
    """

def get_resource_id(resource_instance):
    """
    Get resource ID from instance.
    
    Args:
        resource_instance: Model instance
        
    Returns:
        str: Resource ID
    """

Error Formatting

def format_errors(data):
    """
    Format errors in JSON:API format.
    
    Args:
        data: Error data to format
        
    Returns:
        dict: JSON:API formatted errors
    """

def format_drf_errors(response, context, exc):
    """
    Format Django REST framework errors as JSON:API errors.
    
    Args:
        response: DRF error response
        context: Exception context
        exc: Exception instance
        
    Returns:
        Response: JSON:API formatted error response
    """

Hyperlink Support

class Hyperlink:
    """
    Hyperlink representation for JSON:API links.
    
    Represents hyperlinks in JSON:API responses with href and meta.
    """
    
    def __init__(self, href, meta=None):
        """
        Initialize hyperlink.
        
        Args:
            href: Link URL
            meta: Optional link metadata
        """
        self.href = href
        self.meta = meta

Metadata

JSONAPIMetadata

JSON:API metadata implementation for OPTIONS requests.

class JSONAPIMetadata(SimpleMetadata):
    """
    JSON:API metadata implementation for OPTIONS responses.
    
    Provides field information and relationship metadata
    in a JSON:API compatible format.
    """
    
    type_lookup = {
        # Field type mappings for metadata
    }
    
    relation_type_lookup = {
        # Relationship type mappings
    }
    
    def determine_metadata(self, request, view):
        """
        Generate metadata for view.
        
        Args:
            request: HTTP request
            view: View instance
            
        Returns:
            dict: Metadata information
        """

Settings

JSONAPISettings

Settings management class for JSON:API configuration.

class JSONAPISettings:
    """
    Settings object for JSON:API configuration.
    
    Allows JSON:API settings to be accessed as properties
    with fallback to defaults.
    """
    
    def __init__(self, user_settings=None, defaults=None):
        """
        Initialize settings.
        
        Args:
            user_settings: User-defined settings
            defaults: Default settings
        """
    
    def __getattr__(self, attr):
        """
        Get setting value with fallback to default.
        
        Args:
            attr: Setting name
            
        Returns:
            Setting value
            
        Raises:
            AttributeError: If setting is invalid
        """

Settings Instance

json_api_settings = JSONAPISettings()
"""Global JSON:API settings instance."""

def reload_json_api_settings(*args, **kwargs):
    """
    Reload JSON:API settings when Django settings change.
    
    Connected to Django's setting_changed signal.
    """

Configuration Options

Available JSON:API settings:

# settings.py
JSON_API_FORMAT_FIELD_NAMES = True   # Convert snake_case to kebab-case
JSON_API_FORMAT_TYPES = True         # Format resource type names  
JSON_API_FORMAT_RELATED_LINKS = True # Format related link segments
JSON_API_PLURALIZE_TYPES = True      # Pluralize resource type names
JSON_API_UNIFORM_EXCEPTIONS = True   # Use JSON:API errors everywhere

FORMAT_FIELD_NAMES

# When True:
# Model field: created_at -> JSON:API: "created-at"
# Model field: author_name -> JSON:API: "author-name"

# When False:
# Model field: created_at -> JSON:API: "created_at"
# Model field: author_name -> JSON:API: "author_name"

FORMAT_TYPES

# When True:
# Model: BlogPost -> Resource type: "blog-posts"
# Model: UserProfile -> Resource type: "user-profiles"

# When False:
# Model: BlogPost -> Resource type: "BlogPost"
# Model: UserProfile -> Resource type: "UserProfile"

PLURALIZE_TYPES

# When True:
# Model: Article -> Resource type: "articles"
# Model: Category -> Resource type: "categories"

# When False:
# Model: Article -> Resource type: "article"
# Model: Category -> Resource type: "category"

UNIFORM_EXCEPTIONS

# When True: All views use JSON:API error format
# When False: Only JSON:API views use JSON:API error format

Error Response Format

JSON:API error responses follow this structure:

{
  "errors": [
    {
      "id": "unique-error-id",           # Optional
      "status": "400",                   # HTTP status code
      "code": "validation_error",        # Application-specific error code
      "title": "Validation Error",       # Human-readable title
      "detail": "This field is required.", # Detailed error message
      "source": {                        # Error source information
        "pointer": "/data/attributes/title", # JSON Pointer to error location
        "parameter": "filter[invalid]"   # Query parameter that caused error
      },
      "meta": {                         # Additional metadata
        "field": "title"
      }
    }
  ]
}

Common Error Examples

Validation Errors

# Field validation error
{
  "errors": [{
    "status": "400",
    "detail": "This field is required.",
    "source": {"pointer": "/data/attributes/title"}
  }]
}

# Relationship validation error  
{
  "errors": [{
    "status": "400",
    "detail": "Invalid pk \"999\" - object does not exist.",
    "source": {"pointer": "/data/relationships/author"}
  }]
}

Authentication/Permission Errors

# Authentication required
{
  "errors": [{
    "status": "401",
    "detail": "Authentication credentials were not provided."
  }]
}

# Permission denied
{
  "errors": [{
    "status": "403", 
    "detail": "You do not have permission to perform this action."
  }]
}

Not Found Errors

{
  "errors": [{
    "status": "404",
    "detail": "Not found."  
  }]
}

Types

from rest_framework_json_api.exceptions import (
    exception_handler,
    rendered_with_json_api,
    Conflict
)

from rest_framework_json_api.utils import (
    get_resource_name,
    get_resource_type_from_model,
    get_resource_type_from_serializer,
    get_resource_type_from_instance,
    format_field_names,
    format_field_name,
    undo_format_field_names,
    undo_format_field_name,
    get_serializer_fields,
    get_included_resources,
    format_errors,
    format_drf_errors,
    Hyperlink
)

from rest_framework_json_api.metadata import JSONAPIMetadata
from rest_framework_json_api.settings import (
    JSONAPISettings,
    json_api_settings,
    reload_json_api_settings
)

Install with Tessl CLI

npx tessl i tessl/pypi-djangorestframework-jsonapi

docs

exceptions-utilities.md

filtering.md

index.md

pagination.md

relations.md

renderers-parsers.md

serializers.md

views.md

tile.json