Common JSON Format for Django Rest Framework responses for Android client
Asked Answered
R

5

5

I am developing the rest apis for an android app using Djnago Rest Framework. The android guys told me that it would be nice if I could provide the responses in a common format, like

{
   “Status”:””,
   “Message”:””,
   “Data”:[]
}

Guys, is it the right approach? If so, how to achieve this? My assumption is that using a middleware would be an option.

Thanks in advance.

Rozalin answered 23/2, 2018 at 4:46 Comment(2)
use Serializers, django-rest-framework.org/api-guide/serializersAila
@JerinPeterGeorge, So you are suggesting me to handle this per view?Rozalin
J
11

Writing your own reponse function will not help, in case you are using class based views say APIView or generic views. I think a better way could be to write custom renderer for formatting successfull responses and custom exception handler for responses with errors. This implementation gives you a single point to control all reponses without changing your already existing views. Here is the sample code from one of my project. You need modify it as per your requirements.

Custom Renderer

#renderers.py
class CustomJSONRenderer(JSONRenderer):

def render(self, data, accepted_media_type=None, renderer_context=None):

    response_data = {'message': '', 'errors': [], 'data': data, 'status': 'success'}

    getattr(renderer_context.get('view').get_serializer().Meta,'resource_name', 'objects')

    # call super to render the response
    response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context)

    return response

Custom Exception Handler

# custom_exception_handler.py
def custom_exception_handler(exc, context):
  # Call REST framework's default exception handler first,
  # to get the standard error response.
  response = exception_handler(exc, context)

  # Now add the HTTP status code to the response.
  if response is not None:

    errors = []
    message = response.data.get('detail')
    if not message:
        for field, value in response.data.items():
            errors.append("{} : {}".format(field, " ".join(value)))
        response.data = {'data': [], 'message': 'Validation Error', 'errors': errors, 'status': 'failure'}
    else:
        response.data = {'data': [], 'message': message, 'error': [message], 'success': 'failure'}

  return response

Override REST_FRAMEWORK settings to use these renderer and exception handler.

REST_FRAMEWORK = {
  # Add custom renderer.
  'DEFAULT_RENDERER_CLASSES'=(
              'path.to.CustomJSONRenderer',
              'rest_framework.renderers.JSONRenderer',
              'rest_framework.renderers.BrowsableAPIRenderer'),
  # Add cutom exception handler
  'EXCEPTION_HANDLER': 'path.to.custom_exception_handler'
   }
Journalism answered 23/2, 2018 at 21:8 Comment(2)
You need to check accepted_renderer in custom_exception_handler. If response error, you need to set context['request'].accepted_renderer = renderers.JSONRenderer() (if currrent using renderer is instance of your custom class: if isinstance(context['request'].accepted_renderer, CustomJSONRenderer)) to render correct response, otherwise will response nested dictionary (inside data like example).Bopp
What is this line for in the CustomJSONRenderer? getattr(renderer_context.get('view').get_serializer().Meta,'resource_name', 'objects')Lusaka
F
2

You can write function for customized django rest response and reuse it. Below is the way you can do this.

def custom_response(status_code=status.HTTP_200_OK, message='', data):
    return Response(
        {
             "status": status_code, 
             "message": message, 
              "data": data
        },
        status=status.HTTP_200_OK
    )

In this way response code for request will always be 200 but you can provide what ever code you want in status_code value. You can use this like this.

return custom_response(status_code=status.HTTP_200_OK, message='Data saved successfully', data=my_serialized_data)
Foret answered 23/2, 2018 at 7:25 Comment(4)
Do you follow this approach in your apps? I mean, do you know if it is a necessity to customise the response to this format for mobile clients?Rozalin
Yeah. I am also developing apis for mobile clients and following same approach.Foret
so you add conditional statements in views to check for errors or success?Rozalin
You need to validate provided data so that every parameter is in required form so that no sever error occurs. In case of server error, your view will return response with status code other than 200 and your app will crash.Foret
A
0

Tweaking @Muhammad Hassan answer, i was able to do this

For custom 200 response

def custom200(message, data):
    return Response(
        {
            "status": "Success",
            "status_code": 200,
            "message": message,
            "data": data,
        },
        status=status.HTTP_200_OK,
    )

For custom 400 response

def custom400(message):
    return Response(
        {
            "status": "Failed",
            "status_code": 400,
            "message": message,
        },
        status=status.HTTP_400_BAD_REQUEST,
    )

And use in your viewset like this

return custom200(message="Success Message", data=my_data)
return custom400(message="Error Message ")
Atrocious answered 1/10, 2022 at 20:1 Comment(0)
P
0

Common JSON Format

Success Response for Retrieving a List of Books

    {
  "status": "success",
  "message": "Books retrieved successfully.",
  "data": [
    {
      "id": 1,
      "title": "1984",
      "author": "George Orwell",
      "published_year": 1949
    },
    {
      "id": 2,
      "title": "To Kill a Mockingbird",
      "author": "Harper Lee",
      "published_year": 1960
    }
  ]
}

Error Response for Validation Error

    {
  "status": "error",
  "message": "Validation error occurred.",
  "errors": {
    "title": [
      "This field is required."
    ],
    "published_year": [
      "Ensure this field has at least 4 characters."
    ]
  }
}

Thanks in advance.

Psychasthenia answered 20/5, 2024 at 16:46 Comment(0)
M
-2

Yes its Right way to implement common response.

For that you have to create one Generic class which one is common used while handle API response just you have to pass Different List as your API response.

Your Generic class should be like below.

public class Status<T> {
    @SerializedName("Message")
    @Expose
    private String message;
    @SerializedName("Status")
    @Expose
    private String status;
    @SerializedName("Data")
    @Expose
    private T result;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }
}
Mandola answered 23/2, 2018 at 4:57 Comment(1)
Thank You for your response @mehul-kabaria . But actually I was asking about implementing it in the Django side.Rozalin

© 2022 - 2025 — McMap. All rights reserved.