drf-yasg icon indicating copy to clipboard operation
drf-yasg copied to clipboard

Recursively convert Serializer objects wherever Schema objects are required

Open bobozar opened this issue 5 years ago • 8 comments

I don't understand why I need to pass a serializer to a response variable.

response = {201: MYSERIALIZER}

In my own case, I want to pass data that are not in the serializer. I can't pass dict or str to the response, I keep getting error.

How can I set my custom params or dict in the 'response' variable?

bobozar avatar Aug 13 '18 20:08 bobozar

I don't quite understand. The response of an operation must be an OpenAPI response object with or without a Schema object describing its structure. To achieve this you can either use the openapi.Response helper object, pass a serializer to convert into a schema, pass an openapi.Schema object, or pass a string to generate a response without a body.

All of this is documented under swagger_auto_schema.

axnsan12 avatar Aug 13 '18 20:08 axnsan12

Checked it.. didn't get that part. I want my response to be

 api_response = {'token':'hdhdhd', 'name':'myname'}
 response = {200, api_response} 

I just want to be able to pass my own dict to the response variable. Hope you get my point?

bobozar avatar Aug 13 '18 21:08 bobozar

I don't, really. You don't put a response dictionary into an API schema specification, you describe the structure of that dictionary. You might be looking to set the examples field of the Response object or the example field of the Schema object.

axnsan12 avatar Aug 13 '18 22:08 axnsan12

@bobozar In our project we didn't want to create serializer-per-response either, so we've created a decorator on top of @swagger_auto_schema decorator, with usage like


class SomeAPIView(APIView):
    @schema(
            responses={
                status.HTTP_200_OK: {
                    'fields': serializers.ListField(child=serializers.DictField())
                }
            })
    def get(self, request: Request) -> Response:

And code to convert this thing into serializer is:


def make_serializer(fields: dict, name=None) -> Type[BaseSerializer]:
    # unique name to avoid setting ref_name setting
    cls_name = name or str(int(time.time())) + uuid.uuid4().hex + 'AnonymousSerializer'
    bases = (BaseSerializer,)

    for name, field in fields.items():
        if isinstance(field, type):
            raise ValueError(f'Please, instantiate serializer for {name} for docs to work')

    return type(cls_name, bases, fields)


# start of the snippet inside decorator
_responses = responses

for status_code, response_body_serializer in (_responses or {}).copy().items():
    if isinstance(response_body_serializer, dict):
        serializer_cls = make_serializer(fields=response_body_serializer)
        _responses[status_code] = serializer_cls

# end of the snippet inside decorator

Code probably won't work as is, there's some other stuff going on in BaseSerializer and in the decorator, but you get the idea.

@axnsan12, what do you thing about adding this kind of functionality to the library?

mkurnikov avatar Aug 16 '18 14:08 mkurnikov

I don't see the point. You could just generate an openapi.Schema object instead of a serializer.

axnsan12 avatar Aug 16 '18 14:08 axnsan12

Yes, I understand. But we also validate outcoming response bodies against specified serializers, to make sure docs for responses is correct.

mkurnikov avatar Aug 16 '18 14:08 mkurnikov

And you also can nest serializers inside those dictionaries

responses={
                status.HTTP_200_OK: {'dashboard': DashboardModelSerializer()}
            }

I don't think I can mix openapi.Schema objects and serializers, can I?

UPD. Though we're using python3.6, dictionaries are ordered here, I don't need to worry about messed up order of the fields inside the docs. For <3.6 it could be a problem, so, I'm not really sure.

mkurnikov avatar Aug 16 '18 14:08 mkurnikov

Then I suppose this could be solved by recursively converting Serializer objects to Schema objects wherever a Schema is expected?

axnsan12 avatar Sep 09 '18 20:09 axnsan12