0

I'm building an API using django and the django rest framework. I'm also building a system that will be consuming this API (also Django).

I'm a bit confused as how to implement the serializers on the two servers. So far I've implemented an input and output serializer on both servers. The code example below shows these serializers for a simple example. It takes in a date and a number of days, makes a calculation and returns a new date and the number of holidays between the dates (code does not actually calc this).

There's 4 places where I call a serializer and each time I also have to call the is_valid() method. I'm not sure if all these serializers and calls to is_valid are needed. It all works, but it seems a bit clumsy. Having said that, I'm not sure what other alternatives there are, especially since I need to serialize dates. I guess I can implement my own serializer for dates, but it seems like I'm reinventing the wheel. Then there's also that issue of ensuring the serializtion classes stay the same between the two servers.

My question is basically, is there a recommended approach that should be followed when I'm both the creator and consumer of an API? Do I need all of these serializers? If not, which one(s) can I drop and what should I replace it with?

Note in my actual code I have numerous nested fields in the serializers so it is not as simple as this example.

On my API server I have the following:

from rest_framework import views, serializers
from django.views.decorators.csrf import csrf_exempt
from rest_framework.decorators import api_view

class MyInputSerializer(serializers.Serializer):
    my_date = serializers.DateField()
    days = serializers.IntegerField()

    def do_calc(self):
        my_date = self.validated_data.get('my_date')
        days = self.validated_data.get('days')

        calc_date = my_date  # just as an example
        holidays = days - 2  # just as an example
        result = {
                  'calc_date': calc_date,
                  'holidays': holidays,
                  }
        return MyOutputSerializer(data=result)

class MyOutputSerializer(serializers.Serializer):
    calc_date = serializers.DateField()
    holidays = serializers.IntegerField()


@csrf_exempt
@api_view(['POST'])
def test(request): #/api/v1.0/calc/ maps to this function
    data=request.data
    serializer = MyInputSerializer(data=data)
    if serializer.is_valid(raise_exception=True):
        result = serializer.do_calc()
        if result.is_valid(raise_exception=True): #should always be valid? Needed to access result.data
            return JsonResponse(result.data)

On my normal Django webserver I have the following:

from rest_framework import serializers
from datetime import date
import requests

class MyInputSerializer(serializers.Serializer):
    # same fields as above
    my_date = serializers.DateField()
    days = serializers.IntegerField()


class MyOutputSerializer(serializers.Serializer):
    # same fields as above
    calc_date = serializers.DateField()
    holidays = serializers.IntegerField()


def testing():
    MY_SERVER_URL = 'http://127.0.0.1:8888/api/v1.0/calc/'
    data = {
            'my_date': date(2016, 2, 2),
            'days': 10,
            }
    serializer = MyInputSerializer(data=data)
    if serializer.is_valid(raise_exception=True):
        post_result = requests.post(MY_SERVER_URL, json=serializer.data)
        result = MyOutputSerializer(data=post_result.json())
        if result.is_valid(raise_exception=True):  # This needed?
            calc_date = result.validated_data.get('calc_date')
            holidays = result.validated_data.get('holidays')
            return calc_date, holidays

One other thing, I can create a ModelSerializer on the server with the DB, but then I need to recreate a normal serializer on the other server to deserialize the data. That sort of negates the advantage of the ModelSerializer. How does one typically deal with this problem?

2
  • It would be good to know what exactly your servers are supposed to do and how their interface looks like. Is one of them calculating holidays? So you send a certain json and get a different json back containing a calculation result? Commented Feb 24, 2016 at 9:06
  • That was just an example, but in essence you are correct. The API server only performs calculations, no data can get added to it. As you say, it receives a certain json, does a number of calculations and then returns a totally different json containing the results. Both the incoming and outgoing json contains nested dictionaries and lists, so it's not as simple as the example. The other server (non API) is a normal Django powered website. Commented Feb 24, 2016 at 9:18

2 Answers 2

2

Serializers should do one thing only: serializing data. They should not implement any business logic. As I understand your code example, do_calc is implementing business logic. This is not the correct place, moreover, you actually return the output of a different serializer. This code belongs into the view.

In short, I don't understand why you are using DRF serializers at this point at all. Either you want to use the framework or you simply roll your own logic, wich is perfectly fine. Serialization is not that much work if you only have these two values (unless your example is totally shortened).

Sign up to request clarification or add additional context in comments.

2 Comments

Ok, looking at it again I agree the do_calc method should be somewhere else with the validated data as input. I'm using DRF serializers to serialize my data, give it a bit of structure and perform some validation on the incoming data. My actual calculation could have around 10 values, but some of those values are dictionaries themselves, containing 10 more values. Do you suggest that I rather implement the serialization and deserialization myself?
If you decide to use DRF (it is a very powerful framework) then you should make use of its features as much as possible and appreciate the workload that it takes from your shoulders. Meaning, try not to create your own methods, only override methods if necessary and always be doubtful of every line of code you write yourself: is this really necessary or isn't the framework doing it anyway? For example, I'm not sure about the necessity to call is_valid() (I haven't checked in my own code, yet.)
-1

is_valid only use when you want to update and create a model instance. function do_calc is not proper way to serialize model use to_representation and do your work in that.

1 Comment

I believe to_representaion is a method within each field which gets called when running is_valid. The do_calc function could have been outside of the serializer, it's not serializing the data since there is no model in this example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.