drf-simple-api-errors


Namedrf-simple-api-errors JSON
Version 1.0.1 PyPI version JSON
download
home_pagehttps://github.com/gripep/drf-simple-api-errors
SummaryA library for Django Rest Framework returning consistent and easy-to-parse API error messages.
upload_time2024-04-30 18:44:29
maintainerNone
docs_urlNone
authorGian
requires_python<4.0,>=3.8.1
licenseMIT
keywords python django django rest framework drf error handling errors exceptions
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # Django Rest Framework Simple API Errors

![PyPI](https://img.shields.io/pypi/v/drf-simple-api-errors)
![test workflow](https://github.com/gripep/drf-simple-api-errors/actions/workflows/build.yaml/badge.svg)
[![codecov](https://codecov.io/gh/gripep/drf-simple-api-errors/graph/badge.svg?token=1LJV518KMD)](https://codecov.io/gh/gripep/drf-simple-api-errors)
![pyversions](https://img.shields.io/pypi/pyversions/drf-simple-api-errors.svg)

## 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` but it still serves as a way to include errors in a predictable and easy-to-parse format for any API consumer.

Errors are formatted with RFC7807 keywords and DRF exception data.
This library was designed to be used by anyone who had enough of DRF API error messages format.

## 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 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

```json
{
    "title": "Error message.",
    "detail": [
        "error",
        ...
    ],
    "invalid_params": [
        {
            "name": "field_name",
            "reason": [
                "error",
                ...
            ]
        },
        ...
    ]
}
```

### Example JSON Error Responses

#### Field validation errors

```json
{
    "title": "Error message.",
    "invalid_params": [
        {
            "name": "field_name",
            "reason": [
                "error",
                ...
            ]
        },
        ...
    ]
}
```

#### Non-fields validation errors

```json
{
  "title": "Error message.",
  "detail": [
    "error",
    ...
  ]
}
```

#### Other bad requests with no detail

```json
{
  "title": "Error message."
}
```

## Settings

Default available 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.",
  "invalidParams": [
    {
      "name": "fieldName",
      "reason": [
        "error",
        ...
      ]
    }
    ...
  ]
}
```

- #### EXTRA_HANDLERS

Support for exceptions that differ from the standard structure of the Django Rest Framework.

For instance, you may want to specify you own exception:

```python
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:

```python
def my_func():
    raise AuthenticationFailed(
        {
            "detail": _("Error message."),
            "messages": [
                {
                    "metadata": "metadata_data",
                    "type": "type_name",
                    "message": "error message",
                }
            ],
        }
    )
```

This will result in:

```python
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:

```python
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:

```python
DRF_SIMPLE_API_ERRORS = {
    "EXTRA_HANDLERS": [
        "path.to.my.handlers.handle_exc_custom_authentication_failed",
        # ...
    ]
}
```

- #### 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 with the commands below:

```
make install
make test
```

## 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.8.1",
    "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/58/f9/9154efac828d28b1330cd46a4c77e15633fb9fb5ea60549ecd3e99427671/drf_simple_api_errors-1.0.1.tar.gz",
    "platform": null,
    "description": "# Django Rest Framework Simple API Errors\n\n![PyPI](https://img.shields.io/pypi/v/drf-simple-api-errors)\n![test workflow](https://github.com/gripep/drf-simple-api-errors/actions/workflows/build.yaml/badge.svg)\n[![codecov](https://codecov.io/gh/gripep/drf-simple-api-errors/graph/badge.svg?token=1LJV518KMD)](https://codecov.io/gh/gripep/drf-simple-api-errors)\n![pyversions](https://img.shields.io/pypi/pyversions/drf-simple-api-errors.svg)\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` but it still serves as a way to include errors in a predictable and easy-to-parse format for any API consumer.\n\nErrors are formatted with RFC7807 keywords and DRF exception data.\nThis library was designed to be used by anyone who had enough of DRF API error messages format.\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 typically 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\n- `\"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:\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    \"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}\n```\n\n#### Other bad requests with no detail\n\n```json\n{\n  \"title\": \"Error message.\"\n}\n```\n\n## Settings\n\nDefault available 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  \"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 instance, you may want to specify you own exception:\n\n```python\nclass AuthenticationFailed(exceptions.AuthenticationFailed):\n    def __init__(self, detail=None, code=None):\n        \"\"\"\n        Builds a detail dictionary for the error to give more information\n        to API users.\n        \"\"\"\n        detail_dict = {\"detail\": self.default_detail, \"code\": self.default_code}\n\n        if isinstance(detail, dict):\n            detail_dict.update(detail)\n        elif detail is not None:\n            detail_dict[\"detail\"] = detail\n\n        if code is not None:\n            detail_dict[\"code\"] = code\n\n        super().__init__(detail_dict)\n```\n\nUse exception in code:\n\n```python\ndef my_func():\n    raise AuthenticationFailed(\n        {\n            \"detail\": _(\"Error message.\"),\n            \"messages\": [\n                {\n                    \"metadata\": \"metadata_data\",\n                    \"type\": \"type_name\",\n                    \"message\": \"error message\",\n                }\n            ],\n        }\n    )\n```\n\nThis will result in:\n\n```python\nAuthenticationFailed(\n    {\n        \"detail\": \"Error message.\",\n        \"messages\": [\n            {\n                \"metadata\": \"metadata_data\",\n                \"type\": \"type_name\",\n                \"message\": \"error message\",\n            }\n        ],\n    }\n)\n```\n\nYou can handle this by creating a `handlers.py` file and specifying an handler for your use case:\n\n```python\ndef handle_exc_custom_authentication_failed(exc):\n    from path.to.my.exceptions import AuthenticationFailed\n\n    if isinstance(exc, AuthenticationFailed):\n        try:\n            exc.detail = exc.detail[\"messages\"][0][\"message\"]\n        except (KeyError, IndexError):\n            exc.detail = exc.detail[\"detail\"]\n\n    return exc\n```\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.handlers.handle_exc_custom_authentication_failed\",\n        # ...\n    ]\n}\n```\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 with the commands below:\n\n```\nmake install\nmake test\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": "1.0.1",
    "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": "3da1531c621717b5b6fd0d75d7b152abb77059f5132f4757c9ef1f94c00d8e37",
                "md5": "489cc0f413e294f3b988a16149929bfb",
                "sha256": "5df1018040a4bf9eeb501759a5cf2f50508930254d6ad79195c3046d4439359c"
            },
            "downloads": -1,
            "filename": "drf_simple_api_errors-1.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "489cc0f413e294f3b988a16149929bfb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8.1",
            "size": 9252,
            "upload_time": "2024-04-30T18:44:27",
            "upload_time_iso_8601": "2024-04-30T18:44:27.715907Z",
            "url": "https://files.pythonhosted.org/packages/3d/a1/531c621717b5b6fd0d75d7b152abb77059f5132f4757c9ef1f94c00d8e37/drf_simple_api_errors-1.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "58f99154efac828d28b1330cd46a4c77e15633fb9fb5ea60549ecd3e99427671",
                "md5": "fe0424d9ada5a17698d70661a6fe5105",
                "sha256": "ac6f727c81b866006183fbeb67381cdf0c9af39518654a3482bdc43a0f8b0e88"
            },
            "downloads": -1,
            "filename": "drf_simple_api_errors-1.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "fe0424d9ada5a17698d70661a6fe5105",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8.1",
            "size": 6667,
            "upload_time": "2024-04-30T18:44:29",
            "upload_time_iso_8601": "2024-04-30T18:44:29.373497Z",
            "url": "https://files.pythonhosted.org/packages/58/f9/9154efac828d28b1330cd46a4c77e15633fb9fb5ea60549ecd3e99427671/drf_simple_api_errors-1.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-30 18:44:29",
    "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"
}
        
Elapsed time: 0.24132s