19

Having a hard time configuring Swagger UI Here are the very explanatory docs: https://django-rest-swagger.readthedocs.io/en/latest/

YAML docstrings are deprecated. Does somebody know how to configure Swagger UI from within the python code? or what file should I change to group api endpoints, to add comments to each endpoint, to add query parameter fields in Swagger UI?

Teodor Scorpan
  • 868
  • 1
  • 10
  • 20
  • Do you have an example of the kind of grouping you want to do e.g. on another Swagger-based API? Swagger can be quite limiting in terms of grouping – I wrote bespoke templates to do this. Comments I imagine are added from docstrings on the endpoint methods. Query parameters should appear if they're correctly defined… though I vaguely remember there being circumstances where they're not. – Steve Jul 24 '16 at 09:38

4 Answers4

9

This is how I managed to do it:

base urls.py

urlpatterns = [
...
url(r'^api/', include('api.urls', namespace='api')),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
...
]

api.urls.py

urlpatterns = [
url(r'^$', schema_view, name='swagger'),
url(r'^article/(?P<pk>[0-9]+)/$', 
    ArticleDetailApiView.as_view(actions={'get': 'get_article_by_id'}), 
    name='article_detail_id'),
url(r'^article/(?P<name>.+)/(?P<pk>[0-9]+)/$', 
    ArticleDetailApiView.as_view(actions={'get': 'get_article'}), 
    name='article_detail'),
]

api.views.py. In MyOpenAPIRenderer I update the data dict to add description, query fields and to update type or required features.

class MyOpenAPIRenderer(OpenAPIRenderer):
    def add_customizations(self, data):
        super(MyOpenAPIRenderer, self).add_customizations(data)
        data['paths']['/article/{name}/{pk}/']['get'].update(
            {'description': 'Some **description**',
             'parameters': [{'description': 'Add some description',
                             'in': 'path',
                             'name': 'pk',
                             'required': True,
                             'type': 'integer'},
                            {'description': 'Add some description',
                             'in': 'path',
                             'name': 'name',
                             'required': True,
                             'type': 'string'},
                            {'description': 'Add some description',
                             'in': 'query',
                             'name': 'a_query_param',
                             'required': True,
                             'type': 'boolean'},
                            ]
             })
        # data['paths']['/article/{pk}/']['get'].update({...})
        data['basePath'] = '/api'  

@api_view()
@renderer_classes([MyOpenAPIRenderer, SwaggerUIRenderer])
def schema_view(request):
    generator = SchemaGenerator(title='A title', urlconf='api.urls')
    schema = generator.get_schema(request=request)
    return Response(schema)


class ArticleDetailApiView(ViewSet):

    @detail_route(renderer_classes=(StaticHTMLRenderer,))
    def get_article_by_id(self, request, pk):
        pass

    @detail_route(renderer_classes=(StaticHTMLRenderer,))
    def get_article(self, request, name, pk):
        pass

update for django-rest-swagger (2.0.7): replace only add_customizations with get_customizations.

views.py

class MyOpenAPIRenderer(OpenAPIRenderer):
    def get_customizations(self):
        data = super(MyOpenAPIRenderer, self).get_customizations()
        data['paths'] = custom_data['paths']
        data['info'] = custom_data['info']
        data['basePath'] = custom_data['basePath']
        return data

You can read the swagger specification to create custom data.

bitnik
  • 389
  • 2
  • 5
  • 1
    Where exactly did you find `add_customizations`? I cannot find it in the source code at all. As a result, this solution is not working for me. – Apoorv Kansal Dec 05 '16 at 06:56
  • Not sure what version that this patch relates to but django-rest-swagger==2.1.0 does not contain `add_customizations` or any similar named function that contains the 'data' variable that is described above – oden Dec 15 '16 at 01:12
  • In the last example, is `custom_data` user-defined? – Melvic Ybanez May 12 '17 at 10:16
  • Yes, you can look at swagger specification to create it as mentioned in the answer. – bitnik May 16 '17 at 15:17
7

So, it seems that what happened is django-rest-frameowrk added the new SchemeGenerator, but it is half-baked and missing the ability to generate action descriptions from code docs, and have an open issue about it, due in 3.5.0.

In the meanwhile, django-rest-swagger went ahead and updated their code to work with the new SchemaGenerator, which makes it a breaking change for now.

Very weird series of events led to this ): hoping this will be resolved soon. for now, the proposed answer is the only option.

Daniel Dror
  • 2,304
  • 28
  • 30
7

EDIT - since swagger version 2.2.0 and rest framework 3.9.2 create a custom schema like this:

from rest_framework.schemas import AutoSchema


class CustomSchema(AutoSchema):
    def get_link(self, path, method, base_url):
        link = super().get_link(path, method, base_url)
        link._fields += self.get_core_fields()
        return link

    def get_core_fields(self):
        return getattr(self.view, 'coreapi_fields', ())

Then, just use the DEFAULT_SCHEMA_CLASS setting.

REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'common.schema.CustomSchema',
}

! The below approach is obsolete.

Since I couldn't find any viable option here I simply created my own SchemaGenerator, like this:

from rest_framework.schemas import SchemaGenerator


class MySchemaGenerator(SchemaGenerator):   
    title = 'REST API Index'

    def get_link(self, path, method, view):
        link = super(MySchemaGenerator, self).get_link(path, method, view)
        link._fields += self.get_core_fields(view)
        return link

    def get_core_fields(self, view):
        return getattr(view, 'coreapi_fields', ())

Created the swagger view:

from rest_framework.permissions import AllowAny
from rest_framework.renderers import CoreJSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_swagger import renderers


class SwaggerSchemaView(APIView):
    _ignore_model_permissions = True
    exclude_from_schema = True
    permission_classes = [AllowAny]
    renderer_classes = [
        CoreJSONRenderer,
        renderers.OpenAPIRenderer,
        renderers.SwaggerUIRenderer
    ]

    def get(self, request):
        generator = MySchemaGenerator()
        schema = generator.get_schema(request=request)

        return Response(schema)

Use this view in urls.py:

url(r'^docs/$', SwaggerSchemaView.as_view()),

Add a custom field within an APIView:

class EmailValidator(APIView):
    coreapi_fields = (
        coreapi.Field(
            name='email',
            location='query',
            required=True,
            description='Email Address to be validated',
            type='string'
        ),
    )

    def get(self, request):
        return Response('something')
Lucianovici
  • 314
  • 3
  • 9
0

Using the proposed solution is a bit hacky but works fine, one may face few issues implementing the proposed solution but this doc explains django rest swagger 2 integration as well as the issues faced step by step: Django Rest Swagger 2 comprehensive documentation

Much late but it may help someone looking for help now.

Haziq
  • 2,048
  • 1
  • 16
  • 27