Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

370
Views
Django Rest Framework custom POST URL endpoints with defined parameter (request.POST) with Swagger or other doc

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)

enter image description here

Some Notes:

  • its also noted here that django-rest-swagger was deprecated in June 2019 django-rest-swagger UI doesn't have form for POST request body (function based view)
  • its important to note, its using request.POST (form data) for the parameters https://www.django-rest-framework.org/tutorial/2-requests-and-responses/
  • in Django 1.11.x I was using this swagger_schema.py - https://gist.github.com/axilaris/b7152215a76f6f1f5ffca0436991328d

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="contact@snippets.local"),
      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
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

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="contact@snippets.local"),
      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'),
]
over 4 years ago · Santiago Trujillo Report

0

If you are just wanting something to test the API, Django rest framework actually comes with it's own browsable API. If you set a serializer_class on your APIView then the BrowsableAPIRenderer will figure out all of the relevant details for you.

The following should do the trick:

from rest_framework import serializers, status
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView

class MySerializer(serializers.Serializer):
    token = serializers.CharField()

class MyView(GenericAPIView):

    serializer_class = MySerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        data = serializer.data

        return Response("test_token success", status=status.HTTP_200_OK)
# urls.py
urlpatterns = [
    ...
    path("api/test_token", views.MyView.as_view(), name="test_token")
]

(Notice that in Django 2+ we use path instead of the old url pattern. If you still want to use regex patterns you can use path_re).

The above assumes that you haven't changed the default settings for renderers. The default is:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

Just browse to the relevant end-point and you'll have a nice interface for testing.

Under the hood it is is the fact that the serializer_class is set that enables this. This is the same way that DRF will auto generate a schema for use with something like swagger or redoc.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!