How to generate list of response messages in Django REST Swagger?

前端 未结 1 1927
予麋鹿
予麋鹿 2020-12-23 14:39

I have upgraded Django REST Framework to 3.5.0 yesterday because I need nice schema generation.

I am using Django REST Swagger to document my API b

相关标签:
1条回答
  • 2020-12-23 15:15

    Ah, Finally got it.

    But! This is hack on hack - and probably drf + drf swagger not support that; Basically the problem is not connected to the drf and drf swagger code, rather the openapi codec, see yourself:

    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}
    

    The above code can be found at: openapi_codec/encode.py - github This is not connected in any way with drf or drf swagger - just for each link (eg.: GET /api/v1/test/) create a template with empty description.

    Of course there's a possibility to overcome this issue. But as I said - this is hack on hack :) I will share an example with you:

    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()
    

    What I do in the CustomSchemaGenerator is as follows:

    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.'}
            }
    

    And finally:

    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.'
                    }
                }
            }
        }
    

    I consider this more like fun instead of a real solution. The real solution is probably impossible to achieve at the current state. Maybe you should ask the creators of drf swagger - do they have plans to support responses?

    Anyway, the swagger UI:

    Happy coding :)

    0 讨论(0)
提交回复
热议问题