# Django Rest Framework Simple API Errors


[](https://codecov.io/gh/gripep/drf-simple-api-errors)

## What is this?
A library for [Django Rest Framework](https://www.django-rest-framework.org/) returning **consistent, predictable and easy-to-parse API error messages**.
This library was built with [RFC7807](https://tools.ietf.org/html/rfc7807) guidelines in mind, but with a small twist: it defines a "problem detail" as a list instead of a string, but it still serves as a way to include errors in a human-readable and easy-to-parse format for any API consumer.
Error messages are formatted using RFC7807 keywords and DRF exception data.
Unlike standard DRF, where the error response format varies depending on the error source, this library always returns errors in a consistent and predictable structure.
## What's different?
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` and `rest_framework.errors.ValidationError` to API errors, so you don't have to handle error raised by services/domain logic, `clean()`, etc.
## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Exception Handler](#exception-handler)
- [Error structure overview](#error-structure-overview)
- [Example JSON Error Responses](#example-json-error-responses)
- [Settings](#settings)
- [CAMELIZE](#camelize)
- [EXTRA_HANDLERS](#extra_handlers)
- [FIELDS_SEPARATOR](#fields_separator)
- [Testing](#testing)
- [Support](#support)
- [Contributing](#contributing)
## Installation
Install using the command line:
```
pip install drf-simple-api-errors
```
## Usage
### Exception Handler
Add `EXCEPTION_HANDLER` in your `REST_FRAMEWORK` settings of your Django project settings file:
```python
REST_FRAMEWORK = {
# ...
"EXCEPTION_HANDLER": "drf_simple_api_errors.exception_handler",
}
```
### Error structure overview
API error messages will 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, if any.
- `"invalid_params"` (`list[dict] | None`): A list of dict containing details about parameters that were invalid or malformed in the request, if any. 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.
```json
{
"title": "Error message.",
"detail": [
"error",
...
],
"invalid_params": [
{
"name": "field_name",
"reason": [
"error",
...
]
},
...
]
}
```
### Example JSON Error Responses
#### Field validation errors
```json
{
"title": "Error message.",
"details": null,
"invalid_params": [
{
"name": "field_name",
"reason": [
"error"
// ...
]
}
// ...
]
}
```
#### Non-fields validation errors
```json
{
"title": "Error message.",
"detail": [
"error"
// ...
],
"invalid_params": null
}
```
#### Other bad requests with no detail
```json
{
"title": "Error message.",
"detail": null,
"invalid_params": null
}
```
## Settings
Default settings:
```python
DRF_SIMPLE_API_ERRORS = {
"CAMELIZE": False,
"EXTRA_HANDLERS": [],
"FIELDS_SEPARATOR": ".",
}
```
- #### CAMELIZE
Camel case support for Django Rest Framework exceptions JSON error responses.
If `CAMELIZE` is set to `True`:
```json
{
"title": "Error message.",
"details": null,
"invalidParams": [
{
"name": "fieldName",
"reason": [
"error"
// ...
]
}
// ...
]
}
```
- #### EXTRA_HANDLERS
Support for exceptions that differ from the standard structure of the Django Rest Framework.
For example, if you need to customize how a specific exception is handled or want to format an existing exception differently, you can create your own handler.
To customize error handling for your project, simply create a new file (for example, `extra_handlers.py`) and define your own handler functions. This approach lets you tailor error responses to fit your specific needs.
Then add it to the `EXTRA_HANDLERS` list in this package settings:
```python
DRF_SIMPLE_API_ERRORS = {
"EXTRA_HANDLERS": [
"path.to.my.extra_handlers.custom_handler",
# ...
]
}
```
For reference, this library uses the same pattern for its own extra handlers [here](drf_simple_api_errors/extra_handlers.py).
- #### FIELDS_SEPARATOR
Support for nested dicts containing multiple fields to be flattened.
If `FIELDS_SEPARATOR` is set to `.`:
```python
{
"field1": {
"field2": "value"
}
}
```
Will result in:
```python
{
"field1.field2": "value"
}
```
## Testing
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 during development with the commands below:
```
make install # only if necessary
make test
```
Finally, run `tox` to ensure the changes work for every supported python version:
```
tox -v
```
## Support
Please [open an issue](https://github.com/gripep/drf-simple-api-errors/issues/new).
## Contributing
Please use the [Github Flow](https://guides.github.com/introduction/flow/). In a nutshell, create a branch, commit your code, and open a pull request.
Raw data
{
"_id": null,
"home_page": "https://github.com/gripep/drf-simple-api-errors",
"name": "drf-simple-api-errors",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": "python, django, django rest framework, drf, error handling, errors, exceptions",
"author": "Gian",
"author_email": "30044863+gripep@users.noreply.github.com",
"download_url": "https://files.pythonhosted.org/packages/57/c4/ac0dfeb500c464f465f299d94878f45b2c974402597fa78d89ca5181b05c/drf_simple_api_errors-2.0.0.tar.gz",
"platform": null,
"description": "# Django Rest Framework Simple API Errors\n\n\n\n[](https://codecov.io/gh/gripep/drf-simple-api-errors)\n\n\n## What is this?\n\nA library for [Django Rest Framework](https://www.django-rest-framework.org/) returning **consistent, predictable and easy-to-parse API error messages**.\n\nThis library was built with [RFC7807](https://tools.ietf.org/html/rfc7807) guidelines in mind, but with a small twist: it defines a \"problem detail\" as a list instead of a string, but it still serves as a way to include errors in a human-readable and easy-to-parse format for any API consumer.\nError messages are formatted using RFC7807 keywords and DRF exception data.\n\nUnlike standard DRF, where the error response format varies depending on the error source, this library always returns errors in a consistent and predictable structure.\n\n## What's different?\n\nCompared to other similar and popular libraries, this library:\n\n- Is based on RFC7807 guidelines\n- Aims to provide not only a standardized format for error details, but also human-readable error messages (perfect for both internal and public APIs)\n- Transforms both `django.core.exceptions.ValidationError` and `rest_framework.errors.ValidationError` to API errors, so you don't have to handle error raised by services/domain logic, `clean()`, etc.\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n - [Exception Handler](#exception-handler)\n - [Error structure overview](#error-structure-overview)\n - [Example JSON Error Responses](#example-json-error-responses)\n - [Settings](#settings)\n - [CAMELIZE](#camelize)\n - [EXTRA_HANDLERS](#extra_handlers)\n - [FIELDS_SEPARATOR](#fields_separator)\n- [Testing](#testing)\n- [Support](#support)\n- [Contributing](#contributing)\n\n## Installation\n\nInstall using the command line:\n\n```\npip install drf-simple-api-errors\n```\n\n## Usage\n\n### Exception Handler\n\nAdd `EXCEPTION_HANDLER` in your `REST_FRAMEWORK` settings of your Django project settings file:\n\n```python\nREST_FRAMEWORK = {\n # ...\n \"EXCEPTION_HANDLER\": \"drf_simple_api_errors.exception_handler\",\n}\n```\n\n### Error structure overview\n\nAPI error messages will include the following keys:\n\n- `\"title\"` (`str`): A brief summary that describes the problem type.\n- `\"detail\"` (`list[str] | None`): A list of specific explanations related to the problem, if any.\n- `\"invalid_params\"` (`list[dict] | None`): A list of dict containing details about parameters that were invalid or malformed in the request, if any. Each dict within this list provides:\n - `\"name\"` (`str`): The name of the parameter that was found to be invalid.\n - `\"reasons\"` (`list[str]`): A list of strings describing the specific reasons why the parameter was considered invalid or malformed.\n\n```json\n{\n \"title\": \"Error message.\",\n \"detail\": [\n \"error\",\n ...\n ],\n \"invalid_params\": [\n {\n \"name\": \"field_name\",\n \"reason\": [\n \"error\",\n ...\n ]\n },\n ...\n ]\n}\n```\n\n### Example JSON Error Responses\n\n#### Field validation errors\n\n```json\n{\n \"title\": \"Error message.\",\n \"details\": null,\n \"invalid_params\": [\n {\n \"name\": \"field_name\",\n \"reason\": [\n \"error\"\n // ...\n ]\n }\n // ...\n ]\n}\n```\n\n#### Non-fields validation errors\n\n```json\n{\n \"title\": \"Error message.\",\n \"detail\": [\n \"error\"\n // ...\n ],\n \"invalid_params\": null\n}\n```\n\n#### Other bad requests with no detail\n\n```json\n{\n \"title\": \"Error message.\",\n \"detail\": null,\n \"invalid_params\": null\n}\n```\n\n## Settings\n\nDefault settings:\n\n```python\nDRF_SIMPLE_API_ERRORS = {\n \"CAMELIZE\": False,\n \"EXTRA_HANDLERS\": [],\n \"FIELDS_SEPARATOR\": \".\",\n}\n```\n\n- #### CAMELIZE\n\nCamel case support for Django Rest Framework exceptions JSON error responses.\n\nIf `CAMELIZE` is set to `True`:\n\n```json\n{\n \"title\": \"Error message.\",\n \"details\": null,\n \"invalidParams\": [\n {\n \"name\": \"fieldName\",\n \"reason\": [\n \"error\"\n // ...\n ]\n }\n // ...\n ]\n}\n```\n\n- #### EXTRA_HANDLERS\n\nSupport for exceptions that differ from the standard structure of the Django Rest Framework.\n\nFor example, if you need to customize how a specific exception is handled or want to format an existing exception differently, you can create your own handler.\n\nTo customize error handling for your project, simply create a new file (for example, `extra_handlers.py`) and define your own handler functions. This approach lets you tailor error responses to fit your specific needs.\n\nThen add it to the `EXTRA_HANDLERS` list in this package settings:\n\n```python\nDRF_SIMPLE_API_ERRORS = {\n \"EXTRA_HANDLERS\": [\n \"path.to.my.extra_handlers.custom_handler\",\n # ...\n ]\n}\n```\n\nFor reference, this library uses the same pattern for its own extra handlers [here](drf_simple_api_errors/extra_handlers.py).\n\n- #### FIELDS_SEPARATOR\n\nSupport for nested dicts containing multiple fields to be flattened.\n\nIf `FIELDS_SEPARATOR` is set to `.`:\n\n```python\n{\n \"field1\": {\n \"field2\": \"value\"\n }\n}\n```\n\nWill result in:\n\n```python\n{\n \"field1.field2\": \"value\"\n}\n```\n\n## Testing\n\nAll the necessary commands are included in the `Makefile`.\n\nWe are using `tox` and `poetry` to run tests in every supported Python version.\n\nRun test during development with the commands below:\n\n```\nmake install # only if necessary\nmake test\n```\n\nFinally, run `tox` to ensure the changes work for every supported python version:\n\n```\ntox -v\n```\n\n## Support\n\nPlease [open an issue](https://github.com/gripep/drf-simple-api-errors/issues/new).\n\n## Contributing\n\nPlease use the [Github Flow](https://guides.github.com/introduction/flow/). In a nutshell, create a branch, commit your code, and open a pull request.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A library for Django Rest Framework returning consistent and easy-to-parse API error messages.",
"version": "2.0.0",
"project_urls": {
"Documentation": "https://github.com/gripep/drf-simple-api-errors/blob/master/README.md",
"Homepage": "https://github.com/gripep/drf-simple-api-errors",
"Repository": "https://github.com/gripep/drf-simple-api-errors"
},
"split_keywords": [
"python",
" django",
" django rest framework",
" drf",
" error handling",
" errors",
" exceptions"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e22ef8bf910b89b8dcb70e3fe3e3f274019e7c3446e960beaae3ff31358ee409",
"md5": "fecef1c7de187ddf83822b3523c4ceba",
"sha256": "7e9135ce504e13ed7555e5b8deae6b4745ffa4f7bb530f86e1573bf86e5b19c1"
},
"downloads": -1,
"filename": "drf_simple_api_errors-2.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "fecef1c7de187ddf83822b3523c4ceba",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 13112,
"upload_time": "2025-07-16T18:29:13",
"upload_time_iso_8601": "2025-07-16T18:29:13.442994Z",
"url": "https://files.pythonhosted.org/packages/e2/2e/f8bf910b89b8dcb70e3fe3e3f274019e7c3446e960beaae3ff31358ee409/drf_simple_api_errors-2.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "57c4ac0dfeb500c464f465f299d94878f45b2c974402597fa78d89ca5181b05c",
"md5": "f0c67ac255b9b40d91104103ef350a0a",
"sha256": "f58168275c7ae1cb2c225eba6d3e418a9961bc31737b3114aa0f3c555a8fce9d"
},
"downloads": -1,
"filename": "drf_simple_api_errors-2.0.0.tar.gz",
"has_sig": false,
"md5_digest": "f0c67ac255b9b40d91104103ef350a0a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 11554,
"upload_time": "2025-07-16T18:29:14",
"upload_time_iso_8601": "2025-07-16T18:29:14.496215Z",
"url": "https://files.pythonhosted.org/packages/57/c4/ac0dfeb500c464f465f299d94878f45b2c974402597fa78d89ca5181b05c/drf_simple_api_errors-2.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-16 18:29:14",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "gripep",
"github_project": "drf-simple-api-errors",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"tox": true,
"lcname": "drf-simple-api-errors"
}