uplink icon indicating copy to clipboard operation
uplink copied to clipboard

Support for Django Rest Framework serializers

Open pdrum opened this issue 7 years ago • 3 comments

I am using uplink in a project in order to communicate to an external API. In the project we are using django rest framework. DRF's serializers are much similar to Schemas of marshmallow. For that despite we are using DRF's serializers in other parts of code, for those parts pertinent to making requests and using uplink I had to introduced a new dependency (marshmellow) to the project.

I was wondering if support for serializers of django rest framework could be added along with marshmallow.

Thanks for the perfect library BTW.

pdrum avatar Nov 29 '18 12:11 pdrum

Also speaking of django integration being able to use reverse function or names of urls in @get, @post, etc would be great.

pdrum avatar Nov 29 '18 12:11 pdrum

@pdrum - I don't have much experience using Django REST Framework's Serializers, but having looked at the documentation, I think adding support would definitely be neat!

In fact, you can probably write a custom uplink.converter.Factory to handle this right now! Here's a quick mock up of a converter factory that should add support for DRF's Serializers to your uplink consumer methods (Note: I haven't tested this, so it might contain some errors):

import io

from rest_framework import serializer
from rest_framework.parser import JSONParser
from rest_framework.renderers import JSONRenderer
from uplink import converters, install, utils

class DjangoRestFrameworkSerializerFactory(converters.Factory):
    """Adapter for Django Rest Framework serializers."""
    
    def create_response_body_converter(self, cls, request_definition):
        # Do deserialization of the response body
        if utils.issubclass(cls, serializer.Serializer):
            def parse_response(body):
                stream = io.BytesIO(body)
                data = JSONParser().parse(stream)
                serializer_ = cls(data)
                return serializer_.validated_data
            return parse_response
    
    def create_request_body_converter(self, cls, request_definition):
        # Do serialization of request body.
        if issubclass(cls, serializer.Serializer):
            return JSONRenderer().render

Then, you can set any serializer as the return type of your consumer methods using @returns.json, like so:

import uplink

class TaskApi(Consumer):
   @returns.json
   @get("tasks/{checklist}?due=today")
   def get_pending_tasks(self, checklist) -> TaskSerializer

Finally, make sure to either pass in an instance of the DjangoRestFrameworkSerializerFactory through the converter constructor parameter when you create an instance of your uplink consumer:

consumer = TaskApi(base_url=..., converter=DjangoRestFrameworkSerializerFactory())

Or, use uplink.install at the top of your module to register DjangoRestFrameworkSerializerFactory as a global converter to be used with all consumers you define:

import uplink

uplink.install(DjangoRestFrameworkSerializerFactory())

prkumar avatar Nov 30 '18 06:11 prkumar

@pdrum - We can also look into adding long-term support DRF Serializers; I provide the above converter as a short-term solution so that you don't have to import marshmallow. Notably, I think this support can be implemented as a separate plugin for uplink, sort of like uplink/protobuf.

prkumar avatar Nov 30 '18 06:11 prkumar