kramer65
kramer65

Reputation: 53843

How to get DRF-api in OpenAPI using drf-yasg?

I'm building a simply API using Django Rest Framework. This API does not store anything, but functions as a proxy to another API to query whether a store has milk. So I made a simple serializer and view:

class HasMilkSerializer(serializers.Serializer):
    store = serializers.CharField(min_length=6, max_length=6)
    passage_at = serializers.DateTimeField()

class HasMilkView(CsrfExemptMixin, APIView):
    http_method_names = ['post']
    authentication_classes = [BasicAuthWithKeys]
    serializer_classes = [HasMilkSerializer]

    def post(self, request):
        store = request.data['store']
        visit_at = parser.parse(request.data['visit_at'])
        return Response({'store': store, 'has_milk': has_milk(store, visit_at)})

This works great, so now I want to document this in OpenAPI specs using drf-yasg. I've installed it and swagger shows some info, but it doesn't show any specs on parameters or responses (see screenshot below).

What do I need to do to get swagger to properly document my endpoint? Do I need to define it further in swagger, or do I need to change the endpoint so that swagger can properly document it?

enter image description here

Upvotes: 0

Views: 3105

Answers (2)

Eyob Tariku
Eyob Tariku

Reputation: 66

A couple of things first:

  • In the APIView (or the other classes that inherit from it), the attribute to define the serializer class to be used is serializer_class, not serializer_classes.
  • But since your not using the serializer class here, you really don't need to define it as far as I can see.

As far the question goes, since you are using the APIView class, drf-yasg cannot infer the request & response body using a model queryset. Thus, you have to manually add the response and request body using the swagger_auto_schema decorator. You could do something like this:

from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema


class HasMilkView(CsrfExemptMixin, APIView):
    http_method_names = ['post']
    authentication_classes = [BasicAuthWithKeys]
    serializer_classes = [HasMilkSerializer]
    
    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            required=['store', 'visit_at'],
            properties={
                'store': openapi.Schema(type=openapi.TYPE_STRING,
                                        max_length=6),
                'visit_at': openapi.Schema(type=openapi.TYPE_STRING, 
                                           format=FORMAT_DATE)
            }
        ),
        responses={
            200: openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                    'store': openapi.Schema(type=openapi.TYPE_STRING,
                                        max_length=255),
                    'has_milk': openapi.Schema(type=openapi.TYPE_BOOLEAN)
                }
            )
        }
    )
    def post(self, request):
        store = request.data['store']
        visit_at = parser.parse(request.data['visit_at'])
        return Response({'store': store, 'has_milk': has_milk(store, visit_at)})

Upvotes: 2

xaleqi
xaleqi

Reputation: 221

APIView does not have the serializer_classes attribute and swagger can not detect your serializer automatically. you can use another type of View like GenericAPIView or ModelViewSet.

or

if you want use APIView, you should use @swagger_auto_schema decorator for defining your request/response parameters:

    @swagger_auto_schema(request_body=HasMilkSerializer)
    def post(self, request):
        store = request.data['store']
        visit_at = parser.parse(request.data['visit_at'])
        return Response({'store': store, 'has_milk': has_milk(store, visit_at)})

Upvotes: 3

Related Questions