mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-01-01 18:27:14 -05:00
168 lines
4.6 KiB
Python
168 lines
4.6 KiB
Python
"""
|
|
Standardized API response helpers for ThrillWiki.
|
|
|
|
This module provides consistent response formatting across all API endpoints:
|
|
|
|
Success responses:
|
|
- Action completed: {"detail": "Success message"}
|
|
- With data: {"detail": "...", "data": {...}}
|
|
|
|
Error responses:
|
|
- Validation: {"field": ["error"]} (DRF default)
|
|
- Application: {"detail": "Error message", "code": "ERROR_CODE"}
|
|
|
|
Usage:
|
|
from apps.api.v1.responses import success_response, error_response
|
|
|
|
# Success
|
|
return success_response("Avatar saved successfully")
|
|
|
|
# Error
|
|
return error_response("User not found", code="NOT_FOUND", status_code=404)
|
|
"""
|
|
|
|
from rest_framework import status
|
|
from rest_framework.response import Response
|
|
|
|
|
|
# Standard error codes for machine-readable error handling
|
|
class ErrorCodes:
|
|
"""Standard error codes for API responses."""
|
|
|
|
# Authentication / Authorization
|
|
UNAUTHORIZED = "UNAUTHORIZED"
|
|
FORBIDDEN = "FORBIDDEN"
|
|
INVALID_CREDENTIALS = "INVALID_CREDENTIALS"
|
|
TOKEN_EXPIRED = "TOKEN_EXPIRED"
|
|
TOKEN_INVALID = "TOKEN_INVALID"
|
|
|
|
# Resource errors
|
|
NOT_FOUND = "NOT_FOUND"
|
|
ALREADY_EXISTS = "ALREADY_EXISTS"
|
|
CONFLICT = "CONFLICT"
|
|
|
|
# Validation errors
|
|
VALIDATION_ERROR = "VALIDATION_ERROR"
|
|
INVALID_INPUT = "INVALID_INPUT"
|
|
MISSING_FIELD = "MISSING_FIELD"
|
|
|
|
# Operation errors
|
|
OPERATION_FAILED = "OPERATION_FAILED"
|
|
PERMISSION_DENIED = "PERMISSION_DENIED"
|
|
RATE_LIMITED = "RATE_LIMITED"
|
|
|
|
# User-specific errors
|
|
USER_NOT_FOUND = "USER_NOT_FOUND"
|
|
USER_INACTIVE = "USER_INACTIVE"
|
|
USER_BANNED = "USER_BANNED"
|
|
CANNOT_DELETE_SUPERUSER = "CANNOT_DELETE_SUPERUSER"
|
|
CANNOT_DELETE_SELF = "CANNOT_DELETE_SELF"
|
|
|
|
# Verification errors
|
|
VERIFICATION_EXPIRED = "VERIFICATION_EXPIRED"
|
|
VERIFICATION_INVALID = "VERIFICATION_INVALID"
|
|
ALREADY_VERIFIED = "ALREADY_VERIFIED"
|
|
|
|
# External service errors
|
|
EXTERNAL_SERVICE_ERROR = "EXTERNAL_SERVICE_ERROR"
|
|
CLOUDFLARE_ERROR = "CLOUDFLARE_ERROR"
|
|
|
|
|
|
def success_response(
|
|
detail: str,
|
|
data: dict | None = None,
|
|
status_code: int = status.HTTP_200_OK,
|
|
) -> Response:
|
|
"""
|
|
Create a standardized success response.
|
|
|
|
Args:
|
|
detail: Human-readable success message
|
|
data: Optional additional data to include
|
|
status_code: HTTP status code (default 200)
|
|
|
|
Returns:
|
|
DRF Response object
|
|
|
|
Example:
|
|
return success_response("Avatar saved successfully")
|
|
return success_response("User created", data={"id": user.id}, status_code=201)
|
|
"""
|
|
response_data = {"detail": detail}
|
|
if data:
|
|
response_data.update(data)
|
|
return Response(response_data, status=status_code)
|
|
|
|
|
|
def error_response(
|
|
detail: str,
|
|
code: str | None = None,
|
|
status_code: int = status.HTTP_400_BAD_REQUEST,
|
|
extra: dict | None = None,
|
|
) -> Response:
|
|
"""
|
|
Create a standardized error response.
|
|
|
|
Args:
|
|
detail: Human-readable error message
|
|
code: Machine-readable error code from ErrorCodes
|
|
status_code: HTTP status code (default 400)
|
|
extra: Optional additional data to include
|
|
|
|
Returns:
|
|
DRF Response object
|
|
|
|
Example:
|
|
return error_response("User not found", code=ErrorCodes.NOT_FOUND, status_code=404)
|
|
return error_response("Invalid input", code=ErrorCodes.VALIDATION_ERROR)
|
|
"""
|
|
response_data = {"detail": detail}
|
|
if code:
|
|
response_data["code"] = code
|
|
if extra:
|
|
response_data.update(extra)
|
|
return Response(response_data, status=status_code)
|
|
|
|
|
|
def created_response(detail: str, data: dict | None = None) -> Response:
|
|
"""Convenience wrapper for 201 Created responses."""
|
|
return success_response(detail, data=data, status_code=status.HTTP_201_CREATED)
|
|
|
|
|
|
def not_found_response(detail: str = "Resource not found") -> Response:
|
|
"""Convenience wrapper for 404 Not Found responses."""
|
|
return error_response(
|
|
detail,
|
|
code=ErrorCodes.NOT_FOUND,
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
|
|
def forbidden_response(detail: str = "Permission denied") -> Response:
|
|
"""Convenience wrapper for 403 Forbidden responses."""
|
|
return error_response(
|
|
detail,
|
|
code=ErrorCodes.FORBIDDEN,
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
|
|
|
|
def unauthorized_response(detail: str = "Authentication required") -> Response:
|
|
"""Convenience wrapper for 401 Unauthorized responses."""
|
|
return error_response(
|
|
detail,
|
|
code=ErrorCodes.UNAUTHORIZED,
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
)
|
|
|
|
|
|
__all__ = [
|
|
"ErrorCodes",
|
|
"success_response",
|
|
"error_response",
|
|
"created_response",
|
|
"not_found_response",
|
|
"forbidden_response",
|
|
"unauthorized_response",
|
|
]
|