CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework

Web APIs for Django, made easy.

Pending
Overview
Eval results
Files

status-exceptions.mddocs/

Status Codes and Exceptions

Complete HTTP status code constants and structured exception classes for consistent error handling in Django REST Framework.

Capabilities

HTTP Status Constants

Complete set of HTTP status code constants for consistent API responses.

# Informational responses (1xx)
HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101

# Successful responses (2xx)
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226

# Redirection messages (3xx)
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308

# Client error responses (4xx)
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451

# Server error responses (5xx)
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511

Status Code Utility Functions

Functions for categorizing HTTP status codes.

def is_informational(code):
    """
    Check if HTTP status code is informational (1xx).
    
    Args:
        code (int): HTTP status code
        
    Returns:
        bool: True if code is 1xx
    """

def is_success(code):
    """
    Check if HTTP status code indicates success (2xx).
    
    Args:
        code (int): HTTP status code
        
    Returns:
        bool: True if code is 2xx
    """

def is_redirect(code):
    """
    Check if HTTP status code indicates redirection (3xx).
    
    Args:
        code (int): HTTP status code
        
    Returns:
        bool: True if code is 3xx
    """

def is_client_error(code):
    """
    Check if HTTP status code indicates client error (4xx).
    
    Args:
        code (int): HTTP status code
        
    Returns:
        bool: True if code is 4xx
    """

def is_server_error(code):
    """
    Check if HTTP status code indicates server error (5xx).
    
    Args:
        code (int): HTTP status code
        
    Returns:
        bool: True if code is 5xx
    """

Exception Classes

Structured exception classes for API error handling.

class ErrorDetail(str):
    """
    String subclass that stores an error code in addition to the error message.
    """
    def __new__(cls, string, code=None):
        """
        Create new ErrorDetail instance.
        
        Args:
            string (str): Error message
            code (str): Error code identifier
        """
        self = super().__new__(cls, string)
        self.code = code
        return self
    
    def __eq__(self, other):
        """Compare ErrorDetail instances."""
    
    def __ne__(self, other):
        """Compare ErrorDetail instances."""
    
    def __repr__(self):
        """String representation of ErrorDetail."""
    
    def __hash__(self):
        """Hash for ErrorDetail."""

class APIException(Exception):
    """
    Base class for all API exceptions.
    """
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    default_detail = 'A server error occurred.'
    default_code = 'error'
    
    def __init__(self, detail=None, code=None):
        """
        Initialize API exception.
        
        Args:
            detail (str or dict): Error detail message or dictionary
            code (str): Error code identifier
        """
        if detail is None:
            detail = self.default_detail
        if code is None:
            code = self.default_code
        
        self.detail = _get_error_details(detail, code)
    
    def __str__(self):
        """String representation of exception."""
        return str(self.detail)
    
    def get_codes(self):
        """
        Get error codes from exception detail.
        
        Returns:
            Error codes in same structure as detail
        """
        return _get_codes(self.detail)
    
    def get_full_details(self):
        """
        Get full error details including codes.
        
        Returns:
            Full error details with messages and codes
        """
        return _get_full_details(self.detail)

class ValidationError(APIException):
    """
    Exception for validation errors (400 Bad Request).
    """
    status_code = status.HTTP_400_BAD_REQUEST
    default_detail = 'Invalid input.'
    default_code = 'invalid'

class ParseError(APIException):
    """
    Exception for malformed request data (400 Bad Request).
    """
    status_code = status.HTTP_400_BAD_REQUEST
    default_detail = 'Malformed request.'
    default_code = 'parse_error'

class AuthenticationFailed(APIException):
    """
    Exception for authentication failures (401 Unauthorized).
    """
    status_code = status.HTTP_401_UNAUTHORIZED
    default_detail = 'Incorrect authentication credentials.'
    default_code = 'authentication_failed'

class NotAuthenticated(APIException):
    """
    Exception for missing authentication (401 Unauthorized).
    """
    status_code = status.HTTP_401_UNAUTHORIZED
    default_detail = 'Authentication credentials were not provided.'
    default_code = 'not_authenticated'

class PermissionDenied(APIException):
    """
    Exception for permission errors (403 Forbidden).
    """
    status_code = status.HTTP_403_FORBIDDEN
    default_detail = 'You do not have permission to perform this action.'
    default_code = 'permission_denied'

class NotFound(APIException):
    """
    Exception for resource not found (404 Not Found).
    """
    status_code = status.HTTP_404_NOT_FOUND
    default_detail = 'Not found.'
    default_code = 'not_found'

class MethodNotAllowed(APIException):
    """
    Exception for unsupported HTTP methods (405 Method Not Allowed).
    """
    status_code = status.HTTP_405_METHOD_NOT_ALLOWED
    default_detail = 'Method not allowed.'
    default_code = 'method_not_allowed'
    
    def __init__(self, method, detail=None, code=None):
        """
        Args:
            method (str): HTTP method that was not allowed
            detail: Custom error detail
            code: Custom error code
        """
        if detail is None:
            detail = f'Method "{method}" not allowed.'
        super().__init__(detail, code)

class NotAcceptable(APIException):
    """
    Exception for unsupported media types (406 Not Acceptable).
    """
    status_code = status.HTTP_406_NOT_ACCEPTABLE
    default_detail = 'Could not satisfy the request Accept header.'
    default_code = 'not_acceptable'
    
    def __init__(self, detail=None, code=None, available_renderers=None):
        """
        Args:
            detail: Custom error detail
            code: Custom error code
            available_renderers (list): List of available renderer media types
        """
        self.available_renderers = available_renderers
        super().__init__(detail, code)

class UnsupportedMediaType(APIException):
    """
    Exception for unsupported request media types (415 Unsupported Media Type).
    """
    status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
    default_detail = 'Unsupported media type in request.'
    default_code = 'unsupported_media_type'
    
    def __init__(self, media_type, detail=None, code=None):
        """
        Args:
            media_type (str): Unsupported media type
            detail: Custom error detail
            code: Custom error code
        """
        if detail is None:
            detail = f'Unsupported media type "{media_type}" in request.'
        super().__init__(detail, code)

class Throttled(APIException):
    """
    Exception for rate limit exceeded (429 Too Many Requests).
    """
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_detail = 'Request was throttled.'
    default_code = 'throttled'
    extra_detail_singular = 'Expected available in {wait} second.'
    extra_detail_plural = 'Expected available in {wait} seconds.'
    
    def __init__(self, wait=None, detail=None, code=None):
        """
        Args:
            wait (int): Seconds to wait before next request
            detail: Custom error detail
            code: Custom error code
        """
        if detail is None:
            if wait is not None:
                if wait == 1:
                    detail = self.extra_detail_singular.format(wait=wait)
                else:
                    detail = self.extra_detail_plural.format(wait=wait)
            else:
                detail = self.default_detail
        
        self.wait = wait
        super().__init__(detail, code)

Error Handler Functions

Functions for handling different types of errors.

def server_error(request, *args, **kwargs):
    """
    Generic 500 error handler for API views.
    
    Args:
        request: HTTP request object
        *args: Additional arguments
        **kwargs: Additional keyword arguments
        
    Returns:
        Response: 500 error response
    """

def bad_request(request, exception, *args, **kwargs):
    """
    Generic 400 error handler for API views.
    
    Args:
        request: HTTP request object
        exception: Exception that caused the error
        *args: Additional arguments
        **kwargs: Additional keyword arguments
        
    Returns:
        Response: 400 error response
    """

Usage Examples

Using Status Constants

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
    
    def post(self, request):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    def delete(self, request, pk):
        try:
            book = Book.objects.get(pk=pk)
            book.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except Book.DoesNotExist:
            return Response(
                {'error': 'Book not found'}, 
                status=status.HTTP_404_NOT_FOUND
            )

Raising Custom Exceptions

from rest_framework import exceptions
from rest_framework.views import APIView

class BookView(APIView):
    def get_object(self, pk):
        try:
            return Book.objects.get(pk=pk)
        except Book.DoesNotExist:
            raise exceptions.NotFound('Book not found')
    
    def post(self, request):
        # Validate permissions
        if not request.user.has_perm('myapp.add_book'):
            raise exceptions.PermissionDenied(
                'You do not have permission to create books'
            )
        
        # Validate data
        if not request.data.get('title'):
            raise exceptions.ValidationError({
                'title': ['This field is required.']
            })
        
        # Create book
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        
        # Raise validation error with serializer errors
        raise exceptions.ValidationError(serializer.errors)

Custom Exception Classes

from rest_framework import exceptions, status

class BookNotAvailable(exceptions.APIException):
    status_code = status.HTTP_409_CONFLICT
    default_detail = 'Book is not available for checkout'
    default_code = 'book_not_available'

class LibraryCardExpired(exceptions.APIException):
    status_code = status.HTTP_403_FORBIDDEN
    default_detail = 'Library card has expired'
    default_code = 'card_expired'
    
    def __init__(self, expiry_date=None):
        if expiry_date:
            detail = f'Library card expired on {expiry_date}'
        else:
            detail = self.default_detail
        super().__init__(detail)

# Usage in views
class CheckoutView(APIView):
    def post(self, request):
        book_id = request.data.get('book_id')
        book = Book.objects.get(pk=book_id)
        
        if not book.is_available:
            raise BookNotAvailable()
        
        if request.user.library_card.is_expired:
            raise LibraryCardExpired(request.user.library_card.expiry_date)
        
        # Process checkout
        return Response({'status': 'checked out'})

Exception Detail Structures

from rest_framework import exceptions

# Simple string detail
raise exceptions.ValidationError('Invalid data')
# Response: {"detail": "Invalid data"}

# Dictionary detail for field errors
raise exceptions.ValidationError({
    'title': ['This field is required.'],
    'isbn': ['ISBN must be 13 digits.']
})
# Response: {
#     "title": ["This field is required."],
#     "isbn": ["ISBN must be 13 digits."]
# }

# List detail for multiple errors
raise exceptions.ValidationError([
    'First error message',
    'Second error message'
])
# Response: [
#     "First error message",
#     "Second error message"
# ]

# Error details with codes
from rest_framework.exceptions import ErrorDetail

raise exceptions.ValidationError({
    'title': [ErrorDetail('This field is required.', code='required')],
    'pages': [ErrorDetail('Must be a positive integer.', code='invalid')]
})

Status Code Utilities

from rest_framework import status

def handle_response(response_code):
    if status.is_success(response_code):
        print("Operation successful")
    elif status.is_client_error(response_code):
        print("Client error occurred")
    elif status.is_server_error(response_code):
        print("Server error occurred")
    elif status.is_redirect(response_code):
        print("Redirect required")
    elif status.is_informational(response_code):
        print("Informational response")

# Example usage
handle_response(status.HTTP_201_CREATED)  # "Operation successful"
handle_response(status.HTTP_404_NOT_FOUND)  # "Client error occurred"
handle_response(status.HTTP_500_INTERNAL_SERVER_ERROR)  # "Server error occurred"

Utility Functions

def _get_error_details(data, default_code=None):
    """
    Process error data into ErrorDetail instances.
    
    Args:
        data: Error data (string, dict, or list)
        default_code (str): Default error code
        
    Returns:
        Processed error details
    """

def _get_codes(detail):
    """
    Extract error codes from error detail structure.
    
    Args:
        detail: Error detail structure
        
    Returns:
        Error codes in same structure
    """

def _get_full_details(detail):
    """
    Get full error details including both messages and codes.
    
    Args:
        detail: Error detail structure
        
    Returns:
        Full error details with messages and codes
    """

Install with Tessl CLI

npx tessl i tessl/pypi-djangorestframework

docs

auth-permissions.md

content-negotiation.md

decorators.md

fields-validation.md

generic-views.md

index.md

pagination-filtering.md

request-response.md

routers-urls.md

serializers.md

status-exceptions.md

testing.md

views-viewsets.md

tile.json