简体   繁体   中英

DRF Function Based View custom schema decorator for query parameters in swagger ui

I'd break my brain and loose/waste to much time to manage using Schema Decorator in DRF.

I follow https://www.django-rest-framework.org/topics/documenting-your-api/ and manage it but on sagger-ui and redoc-ui. But GET method query parameters or POST body json string payload aren't documented.

So i'm trying to deal with AutoSchema, ManualSchema and Custom classes to generate api documentation. https://www.django-rest-framework.org/api-guide/views/#view-schema-decorator

But i never manage anything good. and yes i looking through [django-rest-framework] tag on stackoverflow too and yes i open a discussion on DRF google community (but no answers yet).

So what i tried.

Try to deal:

import coreapi
import coreschema
from rest_framework.schemas import AutoSchema, ManualSchema

log_file_delete_schema = AutoSchema(
    manual_fields=[
        coreapi.Field(
            "file_path",
            required=True,
            location="query",
            type="string",
            description="path of the log to be delete",
        )
    ]
)

But it returns "AutoShema as no get_operation" error

Try next:

import coreapi
import coreschema
from rest_framework.schemas import AutoSchema, ManualSchema

class CustomLogFileDeleteSchema(AutoSchema):
    def __init__(self):
        super(CustomLogFileDeleteSchema, self).__init__

    def get_manual_fields(self, path, method):
        extra_fields = [
            coreapi.Field(
                "file_path",
                required=True,
                location="query",
                description="log file path",
                type="string",
                example="/path/to/file/logfile.log",
            )
        ]
        manual_fields = super().get_manual_fields(path, method)
        return manual_fields + extra_fields

It returns to me 'CustomLogFileDeleteSchema' object has no attribute 'instance_schemas'

I tried to use Django Rest Swagger but it's unmaintened project now so ==> next

I'm using function based views for non ORM api endpoint like this:

@api_view(["GET", "POST"])
# @schema(log_file_delete_schema)
#@schema(CustomLogFileDeleteSchema())
@permission_classes((permissions.AllowAny,))
def log_file_delete(request):
    """
    @brief
    Delete the current log file from the device
    @param file_path => this is the log file path to delete
    POST and GET requests only
    e.g. uri looks like <root>/logs/delete/?file_path=/var/log/gpk/core.log
    """
    api_logger.info("access to delete log view")
    method = request.method
    if "GET" == method:
        _arg_file_path = request.GET.get("file_path", None)
    if "POST" == method:
        body_unicode = request.body.decode("utf-8")
        body = json.loads(body_unicode)
        _arg_file_path = body["file_path"]
    if None is _arg_file_path or not _arg_file_path:
        return JsonResponse({"error": "file_path arg is missing or empty"}, status=400)
    try:
        os.remove(Path(_arg_file_path))
        open(_arg_file_path, "w")  # need recreate empty file after delete
        r = {"code": 202, "status_message": "job done! file deleted"}
    except Exception as e:
        r = {
            "code": 400,
            "status_message": "Ooops! there is an error when try to delete logs file %s, {}".format(
                e
            )
            % _arg_file_path,
        }
    return JsonResponse(r, status=r["code"])

The View Schema Decorator example is too light for me, i don't understand what i can do with CustomClass Based on AutoSchema.

Please provide just a better example than inside the documentation about GET query and POST body payload doc in OpenAPI format to manage it un swagger-ui.

图片

i've just opened an issue on github

After many hours to loose my time on github, stackoverflow, google, many dev blogs and forum i find a solution!

Thanks to this article i build OpenAPI dynamically follow docstring as yaml doc. https://www.igeorgiev.eu/python/misc/python-django-rest-framework-openapi-documentation/

So for my case, write yaml format docstring

# declare a subclass of 
from rest_framework.schemas.openapi import AutoSchema
# not a subclass of 
# from rest_framework.schemas import AutoSchema

# don't forget to import yaml from pyyaml package
import yaml

class AutoDocstringSchema(AutoSchema):
    @property
    def documentation(self):
        if not hasattr(self, "_documentation"):
            try:
                self._documentation = yaml.safe_load(self.view.__doc__)
            except yaml.scanner.ScannerError:
                self._documentation = {}
        return self._documentation

    def get_components(self, path, method):
        components = super().get_components(path, method)
        doc_components = self.documentation.get("components", {})
        components.update(doc_components)
        return components

    def get_operation(self, path, method):
        operation = super().get_operation(path, method)
        doc_operation = self.documentation.get(method.lower(), {})
        operation.update(doc_operation)
        return operation

@api_view(["GET", "POST"])
@permission_classes((permissions.AllowAny,))
@schema(AutoDocstringSchema())
def log_file_delete(request):
    """
    get:
      description: delete log file by using get method
      summary: delete log file
      parameters:
        - name: file_path
          in: query
          description: file path of the log to delete
          schema:
            type: string
      responses:
        '200':
          description: log file deleted
          content:
            'application/json': {}
    """
    api_logger.info("access to delete log view")
    method = request.method
    if "GET" == method:
        _arg_file_path = request.GET.get("file_path", None)
    if "POST" == method:
        body_unicode = request.body.decode("utf-8")
        body = json.loads(body_unicode)
        _arg_file_path = body["file_path"]
    if None is _arg_file_path or not _arg_file_path:
        return JsonResponse({"error": "file_path arg is missing or empty"}, status=400)
    try:
        os.remove(Path(_arg_file_path))
        open(_arg_file_path, "w")  # need recreate empty file after delete
        r = {"code": 202, "status_message": "job done! file deleted"}
    except Exception as e:
        r = {
            "code": 400,
            "status_message": "Ooops! there is an error when try to delete logs file %s, {}".format(
                e
            )
            % _arg_file_path,
        }
    return JsonResponse(r, status=r["code"])

NB: in this case i just wrote the yaml doc for the get method.

and then on swagger-ui get the parameter and everything we need

在此处输入图像描述

So i go to github DRF repository add this example and submit PR to update DRF documentation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM