Drf-yasg: For GET request, parsed parameters from request_body are presented as response body

Created on 15 Dec 2017  路  3Comments  路  Source: axnsan12/drf-yasg

View code

from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.views import APIView


class IndexViewSerializer(serializers.Serializer):
    username = serializers.CharField()


class IndexView(APIView):
    @swagger_auto_schema(request_body=IndexViewSerializer)
    def get(self, request):
        pass

swagger spec generated

{
    "swagger":"2.0",
    "info":{
        "title":"Snippets API",
        "version":"v1"
    },
    "host":"localhost:8000",
    "schemes":[
        "http"
    ],
    "basePath":"/",
    "paths":{
        "/index/":{
            "get":{
                "operationId":"index_list",
                "description":"",
                "parameters":[

                ],
                "responses":{
                    "200":{
                        "description":"",
                        "schema":{
                            "type":"array",
                            "items":{
                                "$ref":"#/definitions/IndexView"
                            }
                        }
                    }
                },
                "consumes":[
                    "application/json"
                ],
                "tags":[
                    "index"
                ]
            },
            "parameters":[

            ]
        }
    },
    "definitions":{
        "IndexView":{
            "required":[
                "username"
            ],
            "type":"object",
            "properties":{
                "username":{
                    "type":"string"
                }
            }
        }
    },
    "securityDefinitions":{
        "basic":{
            "type":"basic"
        }
    }
}

As a workaround, I assume, one should specify parameters as openapi.Parameter objects, like

username_param = openapi.Parameter('username', in_=openapi.IN_QUERY, description='Username',
                                   type=openapi.TYPE_STRING)


class IndexView(APIView):
    @swagger_auto_schema(manual_parameters=[username_param])
    def get(self, request):
        pass

which works just fine.

enhancement

Most helpful comment

The problem is in fact that, in django rest framework, there is no way for a view to declare what it returns, so this library assumes that endpoints which receive a request body return it back (for example, ModelViewSet which has a serializer_class which serializes both requests and responses)

For custom views like yours, the right thing is to also explicitly declare your response body in swagger_auto_schema, like for example responses: {200: ''} if it does not match the request body (see documentation here for details on how you can give details about response structure)

On the other hand, HTTP get requests are not usually expected to receive request bodies, that is generally only the case for POST, PUT, PATCH requests.

In your case, where what you really want is a query parameter, the manual_parameters way you gave in your last example is actually the correct way to add it. Giving a serializer to request_body would cause body parameters to be generated, not query parameters, which for GET does not really make sense.

--
Perhaps the conclusion to take from this issue is that a query_serializer option in swagger_auto_schema for generation of query parameters would be a useful addition.

A warning when passing request_body to unappropriate HTTP methods could also be useful.

All 3 comments

The problem is in fact that, in django rest framework, there is no way for a view to declare what it returns, so this library assumes that endpoints which receive a request body return it back (for example, ModelViewSet which has a serializer_class which serializes both requests and responses)

For custom views like yours, the right thing is to also explicitly declare your response body in swagger_auto_schema, like for example responses: {200: ''} if it does not match the request body (see documentation here for details on how you can give details about response structure)

On the other hand, HTTP get requests are not usually expected to receive request bodies, that is generally only the case for POST, PUT, PATCH requests.

In your case, where what you really want is a query parameter, the manual_parameters way you gave in your last example is actually the correct way to add it. Giving a serializer to request_body would cause body parameters to be generated, not query parameters, which for GET does not really make sense.

--
Perhaps the conclusion to take from this issue is that a query_serializer option in swagger_auto_schema for generation of query parameters would be a useful addition.

A warning when passing request_body to unappropriate HTTP methods could also be useful.

Sorry.

Yes, I think query_serializer option would be the best one, as most of HTTP methods could have both query params and body.

Added & uploaded new version.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tiltec picture tiltec  路  4Comments

nicholasgcoles picture nicholasgcoles  路  4Comments

phihag picture phihag  路  3Comments

hnykda picture hnykda  路  3Comments

therefromhere picture therefromhere  路  3Comments