A library for Django Rest Framework returning consistent, predictable and easy-to-parse API error messages.
This library was built with RFC7807 guidelines in mind, but with a small twist: it defines a "problem detail" as a list, but it still serves as a way to include errors in a predictable and easy-to-parse format for any API consumer. Error messages are formatted using RFC7807 keywords and DRF exception data.
Compared to other similar and popular libraries, this library:
- Is based on RFC7807 guidelines
- Aims to provide not only a standardized format for error details, but also human-readable error messages (perfect for both internal and public APIs)
- Transforms both
django.core.exceptions.ValidationError
andrest_framework.errors.ValidationError
to API errors, so you don't have to handle error raised by services/domain logic,clean()
, or other functions/methods
Install using the command line:
pip install drf-simple-api-errors
Add EXCEPTION_HANDLER
in your REST_FRAMEWORK
settings of your Django project settings file:
REST_FRAMEWORK = {
# ...
"EXCEPTION_HANDLER": "drf_simple_api_errors.exception_handler",
}
API error messages typically include the following keys:
"title"
(str
): A brief summary that describes the problem type"detail"
(list[str] | None
): A list of specific explanations related to the problem"invalid_params"
(list[dict] | None
): A list of dict containing details about parameters that were invalid or malformed in the request. Each dict within this list provides:"name"
(str
): The name of the parameter that was found to be invalid"reasons"
(list[str]
): A list of strings describing the specific reasons why the parameter was considered invalid or malformed
{
"title": "Error message.",
"detail": [
"error",
...
],
"invalid_params": [
{
"name": "field_name",
"reason": [
"error",
...
]
},
...
]
}
{
"title": "Error message.",
"invalid_params": [
{
"name": "field_name",
"reason": [
"error",
...
]
},
...
]
}
{
"title": "Error message.",
"detail": [
"error",
...
]
}
{
"title": "Error message."
}
Default available settings:
DRF_SIMPLE_API_ERRORS = {
"CAMELIZE": False,
"EXTRA_HANDLERS": [],
"FIELDS_SEPARATOR": ".",
}
Camel case support for Django Rest Framework exceptions JSON error responses.
If CAMELIZE
is set to True
:
{
"title": "Error message.",
"invalidParams": [
{
"name": "fieldName",
"reason": [
"error",
...
]
}
...
]
}
Support for exceptions that differ from the standard structure of the Django Rest Framework.
For instance, you may want to specify you own exception:
class AuthenticationFailed(exceptions.AuthenticationFailed):
def __init__(self, detail=None, code=None):
"""
Builds a detail dictionary for the error to give more information
to API users.
"""
detail_dict = {"detail": self.default_detail, "code": self.default_code}
if isinstance(detail, dict):
detail_dict.update(detail)
elif detail is not None:
detail_dict["detail"] = detail
if code is not None:
detail_dict["code"] = code
super().__init__(detail_dict)
Use exception in code:
def my_func():
raise AuthenticationFailed(
{
"detail": _("Error message."),
"messages": [
{
"metadata": "metadata_data",
"type": "type_name",
"message": "error message",
}
],
}
)
This will result in:
AuthenticationFailed(
{
"detail": "Error message.",
"messages": [
{
"metadata": "metadata_data",
"type": "type_name",
"message": "error message",
}
],
}
)
You can handle this by creating a handlers.py
file and specifying an handler for your use case:
def handle_exc_custom_authentication_failed(exc):
from path.to.my.exceptions import AuthenticationFailed
if isinstance(exc, AuthenticationFailed):
try:
exc.detail = exc.detail["messages"][0]["message"]
except (KeyError, IndexError):
exc.detail = exc.detail["detail"]
return exc
Then add it to the EXTRA_HANDLERS
list in this package settings:
DRF_SIMPLE_API_ERRORS = {
"EXTRA_HANDLERS": [
"path.to.my.handlers.handle_exc_custom_authentication_failed",
# ...
]
}
Support for nested dicts containing multiple fields to be flattened.
If FIELDS_SEPARATOR
is set to .
:
{
"field1": {
"field2": "value"
}
}
Will result in:
{
"field1.field2": "value"
}
All the necessary commands are included in the Makefile
.
We are using tox
and poetry
to run tests in every supported Python version.
Run test with the commands below:
make install
make test
Please open an issue.
Please use the Github Flow. In a nutshell, create a branch, commit your code, and open a pull request.