Как настроить ответ на ошибку валидации в REST-фреймворке Django?
Я разрабатываю RESTful API с использованием Django REST Framework (DRF), и мне необходимо реализовать общий механизм обработки ошибок для различных ошибок проверки, возникающих в приложении, включая, но не ограничиваясь ошибками аутентификации JWT.
При возникновении ошибок проверки DRF возвращает ответы на ошибки по умолчанию, которые могут быть неудобны для пользователя или не соответствовать различным конечным точкам. Например, при ошибке проверки токена JWT выдается ответ, который выглядит следующим образом:
{
"detail": "Given token not valid for any token type",
"code": "token_not_valid",
"messages": [
{
"token_class": "AccessToken",
"token_type": "access",
"message": "Token is invalid or expired"
}
]
}
Я хотел бы стандартизировать ответы на ошибки во всем моем приложении, чтобы улучшить работу пользователей. В частности, я хочу создать общую функцию, которая может возвращать структурированный ответ на все ошибки проверки в следующем формате:
{
"status": false,
"responseCode": 0,
"message": "Validation ",
"data": {}
}
Я попытался создать custom_exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response is not None:
custom_response_data = {
'status': False,
'responseCode': 0,
'message': 'Validation error',
'data': {}
}
if isinstance(response.data, dict):
errors = {}
for field, detail in response.data.items():
if isinstance(detail, list):
errors[field] = detail[0] if detail else 'Invalid input.'
elif isinstance(detail, dict):
errors[field] = " | ".join(str(v) for v in detail.values())
else:
errors[field] = str(detail)
custom_response_data['message'] = " | ".join(errors.values())
custom_response_data['data'] = errors
response.data = custom_response_data
return response
Но он не дает того, что я хочу
В DRF валидация производится внутри serializer
. В неглубоком примере, предположим, вы хотите сгенерировать JWT-токен для заданного пользователя:
models.py
class JWTExample(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
token = models.UUIDField(default=uuid.uuid4, editable=False)
refresh_token = models.UUIDField(default=uuid.uuid4, editable=False)
views.py
class JWTCreateView(APIView):
def post(self, request, format=None):
serializer = JWTExampleSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
Существует два способа реализации пользовательских валидаторов: либо как function-based
валидатор, либо как class-based
. Для повторного использования вы можете экспортировать эту функцию/класс в файл validators.py
. Поскольку с функциями все понятно, приведем пример с классами:
validators.py
class UserValidator:
def __call__(self, value):
try:
user = get_user_model().objects.get(username=value)
except ObjectDoesNotExist:
message = {
"status": False,
"responseCode": 0,
"message": "Validation ",
"data": {},
}
raise serializers.ValidationError(message)
serializers.py
class JWTExampleSerializer(serializers.Serializer):
user = serializers.CharField()
token = serializers.UUIDField(required=False)
refresh_token = serializers.UUIDField(required=False)
def validate_user(self, value):
validate_user = UserValidator()
validate_user(value)