3

In a simple TokenAuthentication system in Django Rest Framework, the default message when you fail to send a proper authorization token is this

{
"detail": "Authentication credentials were not provided."
}

I want all my API responses to follow a certain template e.g. { success, message, data }

How can I overwrite this error message?

What is the best practice when creating these API templates?

P.S. I checked out other questions but couldn't find anyone with a similar problem. If it was already answered I'd be glad if you could point me to it.

tahmeed156
  • 48
  • 5
  • Have a look at this. This is about overriding default exceptions in drf : [https://stackoverflow.com/questions/33125139/how-to-override-exception-messages-in-django-rest-framework] – Ansuman Apr 25 '20 at 15:28

2 Answers2

3

If you need to change the default message, one way is to implement your own error handler like below:

#your_app/error_handler.py
def custom_exception_handler(exc, context):
      ....
      # ovverride IsAuthenticated permission class exception
      if(response.data['detail'].code == 'not_authenticated'):
          response.data['code'] = Unauthorized.default_code
          response.data['message'] = Unauthorized.default_detail
          del response.data['detail']

      return response

Also, don't forget to add your own error handler in Django's settings.py

REST_FRAMEWORK = {
    "EXCEPTION_HANDLER": ("your_app.error_handler.custom_exception_handler")
}

Moreover, you can implement custom exception classes. For example:

class UnreadableCSVFile(APIException):
    status_code = 400
    default_detail = "Unable to read file."
    default_code = "unreadable_csv_file"
Winston
  • 601
  • 1
  • 9
  • 29
  • Thank you @Winston! And refering to the second question, is there a general way to template all my responses? – tahmeed156 Apr 25 '20 at 15:39
  • You can achieve what you want by implementing your own exception classes and throwing them and also using your own exception handler as I said above. – Winston Apr 25 '20 at 15:44
  • I meant the case where the response is not an exception? For successful requests is there a way I can template it like these exceptions? – tahmeed156 Apr 25 '20 at 15:49
  • Please take a look at [this question](https://stackoverflow.com/questions/53910545/how-overwrite-response-class-in-django-rest-framework-drf) – Winston Apr 25 '20 at 15:58
  • Thanks again, this was exactly what I was looking for! – tahmeed156 Apr 25 '20 at 16:15
  • Thank you for this awesome answer. It worked like a charm for me. If I could just, please, add a detail, I would suggest you to add the import to rest_framework and the recover the thrown exception because this is the best way to solve the problem. – R. Karlus Jun 09 '20 at 17:03
0

For response with no exception

you can use a helper function. something like this.

def render_response(success, data=None, item=None, items=None, err_name=None,
                    err_message=None):
    if success:
        if data is not None:
            return {
                "success": True,
                "data": data
            }
        elif item is not None:
            return {
                "success": True,
                "data": {
                    "item": item
                }
            }
        elif items is not None:
            return {
                "success": True,
                "data": {
                    "items": items
                }
            }
    else:
        return {
            "success": False,
            "error": {
                "name": err_name,
                "message": err_message
            }
        }

and in your return statement for every response, use: return Response(render_response(True, data=serializer.data), status= status.200_OK)

this will give

{
    "success": true,
    "data": {
      ...
    }
}

and this can your standard format.

Ansuman
  • 428
  • 1
  • 4
  • 15