Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django-rest-swagger can't seem to work for me. I can't get it to document anything beyond a title

It seems like django-rest-swagger dropped support for the YAML documentation, and replaced it with a vague non-documented way to do things. I've spent the last 48 hours trying to understand how I can have it document the parameters that go into my post methods.

For instance: I have this:

class user_addresses(APIView):
    """
    get all addresses or post a new one
    """
    authentication_classes = ([JSONWebTokenAuthentication])

    def get(self, request, format=None):
        addresses = Address.objects.filter(owner_id=request.user.id)
        print (addresses)
        serializer = address_serializer(addresses, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = address_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'success': True,
                            'result': serializer.validated_data},
                            status=status.HTTP_201_CREATED)
        return Response({'success': False,
                        'result': serializer.errors},
                        status=status.HTTP_400_BAD_REQUEST)

But the django-rest-swagger will show it as:

All the parameters ignored and there's nothing I can add to it besides the title in my code comment.

Can someone point me in the direction of something that works where I can define all the rich data that swagger allows, like the post field names, if they're mandatory or not. etc. i'm just going crazy here running in circle and can't find anything but complaints that there's no way to do this.

like image 925
JasonGenX Avatar asked Jun 01 '17 23:06

JasonGenX


People also ask

Is Django REST swagger deprecated?

Django REST Swagger: deprecated (2019-06-04) This project is no longer being maintained.

How do I add swagger to Django project?

Update settings.py file in main Django project to load django-rest-swagger app. Update urls.py file in main Django project to first load the get_swagger_view utility function and then add path to route to Swagger UI view. This is where the first hiccup rears it's head.

What is Django REST swagger?

Django REST framework provides the capability to build RESTful (Representational State Transfer) kind of APIs with the Django framework. Swagger UI allows us to build our documentation in the form of HTML pages so it can be viewed and read with ease.

How does Django integrate Swagger UI?

Django Rest Framework + Swagger from rest_framework import routers from yourapp.accounts. views import UserViewSet router = routers. DefaultRouter() router. register(r'users', UserViewSet) urlpatterns = [ url(r'^api/v1/', include(router.


2 Answers

So the idea with the 2.0 update was to use CoreAPI, the "internal" rest framework schema generation, and from it generate the swagger spec.

CoreAPI uses serializer and view classes to do its thing. From serializers it knows what fields are required, what type are those fields and if you want to add your personal description you can do so with help_text parameter:

some_field = serializers.Field(help_text='Field description')

In your case, the problem will be that it won't be able to understand the relationship between the APIView and your serializer. I suggest to take an extra step and move to generic views or viewsets, all of them support serializer_class attribute that can be used for the introspection. For your example something like this should work:

# serializer
class AddressSerializer(serializers.ModelSerializer):

    line1 = serializers.CharField(help_text='Field documentation!')

    class Meta:
        model = Address
        fields = '__all__'
        read_only_fields = 'owner',

    def create(self, validated_data):
        validated_data['owner'] = self.context['request'].user
        return super().create(validated_data)


# api class-based view
class UserAddresses(generics.ListCreateAPIView):
    """
    General API documentation (not wisible in the swagger view)

    get:
    GET-specific documentation!

    Lorem ipsum

    post:
    POST-specific documentation!

    Dolor **sit amet**
    """
    authentication_classes = ([JSONWebTokenAuthentication])
    permission_classes = permissions.IsAuthenticated,
    serializer_class = AddressSerializer

    def get_queryset(self):
        return Address.objects.filter(owner_id=self.request.user.id)

For views there is a specific docstirng format, it's very simple and hopefully, will improve overtime. In any way, you should have a bit more acceptable result now:

enter image description here

like image 133
Igonato Avatar answered Oct 02 '22 13:10

Igonato


A CoreAPI Document can help you make a custom Swagger view. Swagger takes a coreapi json input to render the view - Django Rest Swagger uses the Python bindings of CoreAPI to generate that JSON (https://github.com/core-api/python-client).

What does the coreapi.Document object contain?

For each API, you can create a coreapi.Link() object. Each Link object contains:

  • A URL
  • HTTP Method
  • Description
  • Fields

The list of fields must contain coreapi.Field() objects. A Field object has the parameters:

  • Name
  • Required (whether the field is mandatory)
  • Location (path parameter or query parameter)
  • Description

An Example

A sample Swagger Schema would look something like this, if we were to use CoreAPI:

import coreapi

def api_schema_generator():
    api_schema = coreapi.Document(
        title="My Swagger",
        content={
            "User Addresses": {

                "int_api_get": coreapi.Link(
                    url="/int_api/v1/addresses/",
                    action="get",
                    description="Get addresses of a user",
                    fields=[
                        coreapi.Field(
                            name="user_id",
                            required=True,
                            location="path",
                            description="Unique ID of the user whose addresses are to be found"
                        ),
                    ]
                ),
                "int_api_post": coreapi.Link(
                    url="/int_api/v1/addresses/",
                    action="post",
                    description="Add address for a user",
                    fields=[
                        coreapi.Field(
                            name="user_id",
                            required=True,
                            location="path",
                            description="Unique ID of the user"
                        ),
                        coreapi.Field(
                            name="address",
                            required=True,
                            location="path",
                            description="Address of the user"
                        ),
                    ]
                )
            }
        }
    )
    return api_schema

Our view would take this coreapi.Document object as input. We use the SwaggerUIRenderer, OpenAPIRenderer and CoreJSONRenderer decorators for our view.

views.py:

from rest_framework.decorators import api_view, renderer_classes
from rest_framework_swagger import renderers as swagger_renderer
from rest_framework import renderers

@api_view()
@renderer_classes([renderers.CoreJSONRenderer,
                   swagger_renderer.OpenAPIRenderer,
                   swagger_renderer.SwaggerUIRenderer,
                   ])
def schema_view(request):
    api_schema = api_schema_generator()
    return response.Response(api_schema)

All that we need now is a URL mapping for our view.

urls.py:

from django.conf.urls import include, url

urlpatterns = [
    url(r'^$', views.schema_view),
]

Writing a custom swagger might seem slightly tedious, but you have complete control over what data you want to expose in your Swagger View.

like image 21
xennygrimmato Avatar answered Oct 02 '22 13:10

xennygrimmato