Responses¶
drf-commons enforces a standardized JSON response envelope across all API endpoints. This eliminates the need for client-side conditional parsing based on response structure.
Response Envelope Structure¶
All responses conform to the following schema:
Success:
{
"success": true,
"timestamp": "2026-01-15T10:30:00.000000Z",
"message": "Operation completed successfully.",
"data": { ... }
}
Error:
{
"success": false,
"timestamp": "2026-01-15T10:30:00.000000Z",
"message": "Validation failed.",
"errors": {
"title": ["This field is required."],
"email": ["Enter a valid email address."]
},
"data": null
}
Field |
Type |
Description |
|---|---|---|
|
|
|
|
|
ISO 8601 UTC timestamp of response generation |
|
|
Human-readable description; may be empty on success |
|
|
Response payload; |
|
|
Field-level or non-field errors; present only on error responses |
The timestamp field uses Django’s DjangoJSONEncoder, ensuring UTC
output in ISO 8601 format regardless of the server’s local timezone
configuration.
Response Utility Functions¶
from drf_commons.response import success_response, error_response
success_response¶
success_response(
data=None,
message: str = "",
status_code: int = 200,
**kwargs,
) -> Response
Constructs a DRF Response with the success envelope.
Parameters:
data— The response payload. Passed throughDjangoJSONEncoderserialization. Can be any JSON-serializable value.message— Optional human-readable success message.status_code— HTTP status code. Defaults to200.**kwargs— Additional fields merged into the response envelope.
Examples:
# Simple success
return success_response(data=serializer.data)
# With message and non-200 status
return success_response(
data={"created": 15},
message="Bulk create completed.",
status_code=201,
)
# With additional envelope fields
return success_response(
data=serializer.data,
meta={"total_pages": 10, "current_page": 1},
)
error_response¶
error_response(
message: str = "An error occurred.",
status_code: int = 400,
errors=None,
**kwargs,
) -> Response
Constructs a DRF Response with the error envelope.
Parameters:
message— Human-readable error description.status_code— HTTP status code. Defaults to400.errors— Dict of field-level or non-field errors.**kwargs— Additional fields merged into the response envelope.
Examples:
# Validation error
return error_response(
message="Validation failed.",
errors=serializer.errors,
status_code=400,
)
# Not found
return error_response(
message="Article not found.",
status_code=404,
)
# Permission denied
return error_response(
message="You do not have permission to perform this action.",
status_code=403,
)
Automatic Response Formatting¶
When using drf-commons ViewSets, response formatting is automatic. The CRUD
and bulk action mixins call success_response() and error_response()
internally. No per-view code is required for standard operations.
Custom views and actions can use the utilities directly:
from rest_framework.decorators import action
from drf_commons.response import success_response, error_response
from drf_commons.views import BaseViewSet
class ReportViewSet(BaseViewSet):
@action(detail=False, methods=["post"], url_path="generate")
def generate_report(self, request):
try:
result = ReportService.generate(request.data)
return success_response(
data=result,
message="Report generated successfully.",
)
except ValueError as exc:
return error_response(
message=str(exc),
status_code=422,
)
Pagination Response Format¶
Paginated list responses include standard pagination metadata alongside
the data array:
{
"success": true,
"timestamp": "2026-01-15T10:30:00.000000Z",
"message": "",
"count": 150,
"next": "https://api.example.com/articles/?page=3",
"previous": "https://api.example.com/articles/?page=1",
"data": [ ... ]
}
For unpaginated list responses (?paginated=false or when
pagination_class = None), the count, next, and previous fields
are absent and data contains the full array.