2016-10-21 33 views
18

Zaktualizowałem Django Rest Framework do 3.5.0, ponieważ potrzebuję ładnego generowania schematu.Jak wygenerować listę komunikatów odpowiedzi w django rest swagger?

Używam Django Rest Swagger do udokumentowania mojego interfejsu API, ale nie wiem, jak wyświetlić listę wszystkich możliwych komunikatów odpowiedzi dostarczanych przez punkt końcowy interfejsu API.

Wygląda na to, że jest automatyczne generowanie komunikatu o powodzeniu odpowiadającego działaniu wykonywanemu przez mój punkt końcowy. Akcje POST generują 201 kodów odpowiedzi, bez żadnego opisu.

enter image description here

Jak bym go o dodanie wszystkich wiadomości odpowiedzi, że mój punkt końcowy dostarcza i dać im trochę opisów?

Używam

djangorestframework==3.5.0

django-rest-swagger==2.0.7

Odpowiedz

16

Ach, wreszcie dostał.

Ale! To jest hack na hack - i prawdopodobnie drf + drf swagger nie obsługuje tego; W zasadzie problem nie jest związany z kodem drf i drf Swagger, raczej kodeka OpenAPI, sami zobaczcie:

def _get_responses(link): 
    """ 
    Returns minimally acceptable responses object based 
    on action/method type. 
    """ 
    template = {'description': ''} 
    if link.action.lower() == 'post': 
     return {'201': template} 
    if link.action.lower() == 'delete': 
     return {'204': template} 
    return {'200': template} 

Powyższy kod można znaleźć na stronie: openapi_codec/encode.py - github To nie jest połączony w żaden sposób z FRD lub drff swagger - tylko dla każdego linku (np .: GET/api/v1/test /) stwórz szablon z pustym opisem.

Oczywiście istnieje możliwość rozwiązania tego problemu. Ale jak powiedziałem - to siekać na włamania :) będę dzielić przykład z wami

docs_swagger.views.py

from rest_framework import exceptions 
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 

from docs_swagger.schema_generator import CustomSchemaGenerator 


def get_swagger_view(title=None, url=None): 
    """ 
    Returns schema view which renders Swagger/OpenAPI. 

    (Replace with DRF get_schema_view shortcut in 3.5) 
    """ 
    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 = CustomSchemaGenerator(title=title, url=url) # this is altered line 
      schema = generator.get_schema(request=request) 
      if not schema: 
       raise exceptions.ValidationError(
        'The schema generator did not return a schema Document' 
       ) 
      return Response(schema) 

    return SwaggerSchemaView.as_view() 

Co zrobić w CustomSchemaGenerator jest następujący:

docs_swagger.schema_generator.py

import urlparse 
import coreapi 
from rest_framework.schemas import SchemaGenerator 

from openapi_codec import encode 


def _custom_get_responses(link): 
    detail = False 
    if '{id}' in link.url: 
     detail = True 
    return link._responses_docs.get(
     '{}_{}'.format(link.action, 'list' if not detail else 'detail'), 
     link._responses_docs 
    ) 


# Very nasty; Monkey patching; 
encode._get_responses = _custom_get_responses 


class CustomSchemaGenerator(SchemaGenerator): 

    def get_link(self, path, method, view): 
     """ 
     Return a `coreapi.Link` instance for the given endpoint. 
     """ 
     fields = self.get_path_fields(path, method, view) 
     fields += self.get_serializer_fields(path, method, view) 
     fields += self.get_pagination_fields(path, method, view) 
     fields += self.get_filter_fields(path, method, view) 

     if fields and any([field.location in ('form', 'body') for field in fields]): 
      encoding = self.get_encoding(path, method, view) 
     else: 
      encoding = None 

     description = self.get_description(path, method, view) 

     if self.url and path.startswith('/'): 
      path = path[1:] 

     # CUSTOM 
     data_link = coreapi.Link(
      url=urlparse.urljoin(self.url, path), 
      action=method.lower(), 
      encoding=encoding, 
      fields=fields, 
      description=description 
     ) 

     data_link._responses_docs = self.get_response_docs(path, method, view) 

     return data_link 

    def get_response_docs(self, path, method, view): 
     return view.responses_docs if hasattr(view, 'responses_docs') else {'200': { 
      'description': 'No response docs definition found.'} 
     } 

i wreszcie:

my_view.py

class TestViewSet(viewsets.ModelViewSet): 
    queryset = Test.objects.all() 
    serializer_class = TestSerializer 

    responses_docs = { 
     'get_list': { 
      '200': { 
       'description': 'Return the list of the Test objects.', 
       'schema': { 
        'type': 'array', 
        'items': { 
         'type': 'object', 
         'properties': { 
          'id': { 
           'type': 'integer' 
          } 
         } 
        } 
       } 
      }, 
      '404': { 
       'description': 'Not found', 
       'schema': { 
        'type': 'object', 
        'properties': { 
         'message': { 
          'type': 'string' 
         } 
        } 
       }, 
       'example': { 
        'message': 'Not found.' 
       } 
      } 
     }, 
     'get_detail': { 
      '200': { 
       'description': 'Return single Test object.', 
       'schema': { 
        'type': 'object', 
        'properties': { 
         'id': { 
          'type': 'integer' 
         } 
        } 
       } 
      }, 
      '404': { 
       'description': 'Not found.', 
       'schema': { 
        'type': 'object', 
        'properties': { 
         'message': { 
          'type': 'string' 
         } 
        } 
       }, 
       'example': { 
        'message': 'Not found.' 
       } 
      } 
     } 
    } 

Uważam, że to bardziej zabawa niż prawdziwe rozwiązanie. Rzeczywiste rozwiązanie jest prawdopodobnie niemożliwe do osiągnięcia w obecnym stanie. Może powinieneś zapytać twórców drff bełkotać - czy oni mają plany wspierania odpowiedzi?

Zresztą UI swagger: enter image description here

Szczęśliwy kodowania :)

+5

"? Może powinieneś zapytać twórców DRF puszyć - Czy oni mają plany wspierania reakcji" - Dokładnie. Schemat generowania schematu REST nie * jeszcze * zawiera żadnych informacji o schemacie odpowiedzi. Wersja 3.6 systemu Django REST * może * działać, chociaż jeszcze nie jest podana. –

+0

Hej Sebastian, bardzo dziękuję za rozwiązanie. Jak Tom stwierdził, że nie jest to dane, że schemat poprawnej odpowiedzi zostanie wysłany w wersji 3.6, będę intensywnie wykorzystywać twoją odpowiedź do wdrożenia niestandardowego schematu odpowiedzi. – Erika

+1

Definiowanie schematu typu 'list' z' items' typu 'object' nie wyświetlało listy obiektów w interfejsie użytkownika. Zamiast tego otrzymuję tylko "listę" tekstu. To działa dobrze, gdy zmieniłem wartość 'type' na' tablica' zamiast na 'list'. –