previously in Django 1.11, I'ved defined Django REST API in this way:
in url.py
url(r'^api/test_token$', api.test_token, name='test_token'),
in api.py
@api_view(['POST'])
def test_token(request):
# ----- YAML below for Swagger -----
"""
description: test_token
parameters:
- name: token
type: string
required: true
location: form
"""
token = request.POST['token']
return Response("test_token success", status=status.HTTP_200_OK)
Now that I am migrating to Django 3.1.5, I'd like to know how the above can be achieved in the same way with Django Rest Framework (DRF). In the above particular case, it is POST API "test_token" that takes in one parameter. And generate API documentation like swagger/redoc (that can be used for testing the API)
Some Notes:
How can I implement this on Django 3.x ? (as in the title: Django Rest Framework custom POST URL endpoints with defined parameter with Swagger or other doc)
UPDATE:
I think there is some form of solution from here: https://github.com/tfranzel/drf-spectacular/issues/279
As I have a whole lot of APIs that uses @api_view, the changes docstring to the decorator @extend_schema may be simplest migration path. I hope someone can provide guidance on url.py to the conversion using @extend_schema. This is to get the url end points and swagger implemented. Thanks.
This is closest I'ved got with drf-spectacular however
@extend_schema(
parameters=[OpenApiParameter(
name='token',
type={'type': 'string'},
location=OpenApiParameter.QUERY,
required=False,
style='form',
explode=False,
)],
responses=OpenApiTypes.OBJECT,
)
@api_view(['POST'])
def test_api(request):
# ----- YAML below for Swagger -----
"""
description: test_api
parameters:
- name: token
type: string
required: true
location: form
"""
token = request.POST['token']
return Response("success test_api:" + token, status=status.HTTP_200_OK)
its giving this (which is incorrect), notice the token query
curl -X POST "http://localhost:8000/api/test_token/?token=hello" -H "accept: application/json" -H "X-CSRFToken: JyPOSAQx04LK0aM8IUgUmkruALSNwRbeYDzUHBhCjtXafC3tnHRFsxvyg5SgMLhI" -d ""
instead of a POST input param (how to get this ?)
curl -X POST --header 'Content-Type: application/x-www-form-urlencoded' --header 'Accept: application/json' --header 'X-CSRFToken: aExHCSwrRyStDiOhkk8Mztfth2sqonhTkUFaJbnXSFKXCynqzDQEzcRCAufYv6MC' -d 'token=hello' 'http://localhost:8000/api/test_token/
THE SOLUTION:
url.py
from drf_yasg.utils import swagger_auto_schema
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import parser_classes
from rest_framework.parsers import FormParser
token = openapi.Parameter('token', openapi.IN_FORM, type=openapi.TYPE_STRING, required=True)
something = openapi.Parameter('something', openapi.IN_FORM, type=openapi.TYPE_INTEGER, required=False)
@swagger_auto_schema(
method="post",
manual_parameters=[token, something],
operation_id="token_api"
)
@api_view(['POST'])
# this is optional and insures that the view gets formdata
@parser_classes([FormParser])
def token_api(request):
token = request.POST['token']
something = request.POST['something']
return Response("success test_api:" + token + something, status=status.HTTP_200_OK)
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="[email protected]"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
path('token_api', token_api, name='token_api'),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
] + required_urlpatterns
As you said django-rest-swagger is deprecated.
That's why it is recommended to use drf-yasg.
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
class ArticleViewSet(viewsets.ModelViewSet):
@swagger_auto_schema(request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'test_token': openapi.Schema(type=openapi.TYPE_STRING, description='string'),
}
))
def create(self, request, *args, **kwargs):
...
Or if you want to use a DRF action
@swagger_auto_schema(method="post", request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'test_token': openapi.Schema(type=openapi.TYPE_STRING, description='string'),
}
))
@action(method=["post"], detail=False)
def my_post_action(self, request, *args, **kwargs):
...
Or with api view:
# here we define that this view accepts a json (or object parameter) that has test_token parameter inside of it
@swagger_auto_schema(method='post',
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT, # object because the data is in json format
properties={
'test_token': openapi.Schema(type=openapi.TYPE_STRING, description='this test_token is used for...'),
}
), operation_id="token_view")
# your view
@api_view(['POST'])
def token_view(request):
pass
And your url.py will look like so
# define some basic info about your api for swagger
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="[email protected]"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
# define your api view url
path('token_view/', token_view),
# define the url of the swagger ui
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]