Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation codes and messages in Django Rest Framework

Using out of the box fields in a serializer, validation error messages look something like this:

{
    "product": [
        "This field must be unique."
    ],
    "price": [
        "This field is required."
    ]
}

However, for the API I am writing, I would like to provide a unique error code for each failed validation, so that clients can programmatically respond to validation errors, or can provide their own custom messages in a UI. Ideally the error json would look something like this:

{
    "product": [
        {
          "code": "unique",
          "message": "This field must be unique."
        }
    ],
    "price": [
        { 
          "code": "required",
          "message": "This field is required."
        }
    ]
}

The current approach using ValidationErrors makes this rather difficult. Looking through the code, it seems as though this type of error reporting is not supported currently. However, I'm looking for an approach to override the error handling to fit this model.

like image 717
Justin Harris Avatar asked Jan 26 '15 17:01

Justin Harris


People also ask

How do I validate an email in Django REST Framework?

After opening the activation link in the web browser, the request is sent to the web application (Django Rest Framework). The web server compares the token from the activation URL with the token stored in the database. If they are the same, the email address is verified.

How does Django validate data in serializer?

Validation in Django REST framework serializers is handled a little differently to how validation works in Django's ModelForm class. With ModelForm the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class.

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.

How do you validate data in DRF?

DRF enforces data validation in the deserialization process, which is why you need to call is_valid() before accessing the validated data. If the data is invalid, errors are then appended to the serializer's error property and a ValidationError is thrown. There are two types of custom data validators: Custom field.


2 Answers

This question was posted quite a while ago, so I will add the updated answer here. Newer versions of DRF now support this, but it still takes a bit of custom code. Creating a new exception handler with do the trick:

from rest_framework.views import exception_handler
from rest_framework.exceptions import APIException


def full_details_exception_handler(exc, context):
    """
    This overrides the default exception handler to
    include the human-readable message AND the error code
    so that clients can respond programmatically.
    """
    if isinstance(exc, APIException):
        exc.detail = exc.get_full_details()

    return exception_handler(exc, context)

Then configure DRF to use that custom handler in your settings:

REST_FRAMEWORK['EXCEPTION_HANDLER'] = 'my_module.full_details_exception_handler'

It would be nice if this configuration were available in DRF itself to just add it as a configuration option, but this is a pretty lightweight solution to include the error codes.

like image 126
Justin Harris Avatar answered Oct 29 '22 12:10

Justin Harris


Add something like this to your serializer:

def is_valid(self, raise_exception=False):
    try:
        return super(ClientSerializer, self).is_valid(raise_exception)
    except exceptions.ValidationError as e:
        if 'email' in e.detail:
            for i in range(len(e.detail['email'])):
                if e.detail['email'][i] == UniqueValidator.message:
                    e.detail['email'][i] = {'code': 'not-unique'}
        raise e
like image 39
WhyNotHugo Avatar answered Oct 29 '22 11:10

WhyNotHugo