Maison  >  Article  >  développement back-end  >  Voir la documentation de l'interface de gestion

Voir la documentation de l'interface de gestion

coldplay.xixi
coldplay.xixiavant
2020-09-04 16:30:003499parcourir

Voir la documentation de l'interface de gestion

Recommandations d'apprentissage associées : Tutoriel Python

Dans la plupart des cas, l'interface développée n'est pas destinée au développement de cette interface. utilisez-le, donc s'il n'y a pas de document d'interface, les autres ne sauront pas quelles interfaces peuvent être appelées. Même si vous connaissez l'URL de l'interface, il est difficile de savoir quels paramètres l'interface requiert. peut-être pas en mesure de comprendre la signification de ces paramètres. Le document d’interface doit donc être une configuration essentielle pour le projet.

Il existe de nombreuses façons d'écrire des documents d'interface. La manière la plus simple et la plus directe consiste à ouvrir un bloc-notes ou un document Word et à noter les détails et l'utilisation de l'interface. D'autres peuvent se référer à ce document pour appeler l'interface. . Bien que cela soit simple, les inconvénients sont également évidents : d'abord, cela nécessite d'écrire beaucoup de texte de description, ce qui est très ennuyeux, mais en fait, ces informations ont été reflétées dans le code, ce qui est un peu comme utiliser un langage naturel pour écrire le code à nouveau ; deuxièmement, une fois que l'interface est mise à jour, le document d'interface doit être mis à jour manuellement de manière synchrone. Les développeurs peuvent facilement l'oublier, ce qui entraîne une incohérence entre le contenu du document d'interface et la fonction réelle de l'interface.

Étant donné que de nombreuses informations d'interface sont réellement reflétées dans le code, les gens se demandent naturellement s'ils peuvent extraire automatiquement les informations pertinentes directement du code écrit pour générer des documents. Le document d'interface sera également automatiquement mis à jour, les deux problèmes mentionnés ci-dessus peuvent être résolus.

Bien entendu, l'écriture de documents d'interface n'est pas une création littéraire. Afin d'extraire automatiquement des informations directement du code écrit pour générer des documents, il doit exister un format de document standard, sinon l'outil ne saura pas quoi extraire. le code. Après avoir extrait les informations, je ne sais pas comment les organiser.

Grâce aux efforts de tous, il existe désormais de nombreuses normes de documents d'interface et outils de génération matures. Parmi eux, la spécification OpenAPI est une norme largement acceptée et utilisée. L'outil d'automatisation de documents utilisé par notre interface de blog sera également basé sur The. La norme OpenAPI extrait les informations de documentation du code et les organise dans le format standard d'OpenAPI.

Conseils :

Un terme plus familier lié à OpenAPI est swagger. Swagger propose une série d'outils gratuits et open source liés à l'OpenAPI. La société derrière eux est SMARTBEAR, connue comme le leader du secteur du développement d'outils de qualité de code.

Introduction à OpenAPI

Le document d'interface n'est pas une œuvre littéraire et le contenu dont il a besoin est fondamentalement fixe. Par exemple, pour une interface RESTful, il vous suffit de connaître les informations clés suivantes pour terminer l'appel. À leur tour, ces informations peuvent définir une interface complète de style RESTful :

  • La méthode HTTP et l'URL demandées.
  • Paramètres reçus (y compris les paramètres de chemin et les paramètres de requête dans l'URL ; les paramètres d'en-tête de requête HTTP ; le corps de la requête HTTP et d'autres paramètres).
  • Le contenu renvoyé par l'interface.

OpenAPI a standardisé les informations ci-dessus et proposé la spécification OpenAPI. Tant que le contenu du document répond à cette norme, les outils OpenAPI peuvent le traiter. Par exemple, les outils de document visuel peuvent lire le contenu du document et générer. Documentation au format HTML.

Remarque :

La dernière version de la spécification OpenAPI est la 3, mais la plupart des outils en prennent actuellement en charge 2, et la bibliothèque utilisée dans le didacticiel n'en prend en charge que 2.

drf-yasg

drf-yasg est une application tierce pour Django. Elle peut extraire automatiquement les informations d'interface du code écrit par le framework django-rest-framework pour générer des documents conformes. avec la norme OpenAPI. Nous l'utiliserons pour générer la documentation d'interface pour l'application de blog.

La première étape est bien sûr d'installer drf-yasg, d'entrer dans le répertoire racine du projet, d'exécuter la commande :

Onglet Commande

Linux/macOS
$ pipenv install drf-yasg复制代码
Windows
...\> pipenv install drf-yasg复制代码

Puis ajoutez drf-yasg au INSTALLED_APPS configuration Dans la rubrique :

# filename="blogproject/settings/common.py"INSTALLED_APPS = [    # 其它已添加的应用...
        "pure_pagination",  # 分页
    "haystack",  # 搜索
    "drf_yasg", # 文档]复制代码

Utilisez ensuite la fonction fournie par drf_yasg pour créer une vue django. Cette vue renverra le contenu du document au format HTML, afin que l'on puisse visualiser le document d'interface du blog directement dans. le navigateur :

# filename="blogproject/urls.py"from django.urls import include, path, re_pathfrom drf_yasg import openapifrom drf_yasg.views import get_schema_viewfrom rest_framework import permissions, routers


schema_view = get_schema_view(
    openapi.Info(
        title="HelloDjango REST framework tutorial API",
        default_version="v1",
        description="HelloDjango REST framework tutorial AP",
        terms_of_service="",
        contact=openapi.Contact(email="zmrenwu@163.com"),
        license=openapi.License(name="GPLv3 License"),
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [    # 其它已注册的 URL 模式...
  
    # 文档
    re_path(        r"swagger(?P<format>\.json|\.yaml)",
        schema_view.without_ui(cache_timeout=0),
        name="schema-json",
    ),
    path(        "swagger/",
        schema_view.with_ui("swagger", cache_timeout=0),
        name="schema-swagger-ui",
    ),
    path("redoc/", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"),
]复制代码

Il vous suffit d'utiliser get_schema_view pour générer une vue du document, puis nous mappons cette fonction d'affichage sur 4 URL.

Entrez maintenant dans le répertoire racine du projet et démarrez le serveur de développement :

Onglet Commande

Linux/macOS
$ pipenv run python manage.py runserver复制代码
rrree

Visitez ensuite http://127.0.0.1:8000/swagger/ ou http : // 127.0.0.1:8000/redoc/, vous pouvez voir le document d'interface au format HTML généré automatiquement par drf-yasg. Si vous visitez http://127.0.0.1:8000/swagger.json ou http://127.0.0.1:8000/swagger.yaml, vous pouvez voir le document standard OpenAPI d'origine et swagger et redoc sont tous deux générés sur la base de cette norme. document. Interface utilisateur visuelle.

完善文档

drf-yasg 毕竟不是使用人工智能开发的,即使是使用人工智能,也很难做到 100% 的正确,毕竟由人类写的代码可能是千变万化的,工具无法预料到所有可能的情况,一旦它遇到无法处理的地方,自动生成的文档就可能出错,或者生成的内容不符合我们的预期。

我们不妨访问 http://127.0.0.1:8000/swagger/ 先来看看没做任何定制化之前生成的效果。可以看到内容大体上是正确的,接口基本上都罗列了出来,但是仔细检查各个接口的内容,就会发现一些问题:

  1. GET /api-version/test/ 这个接口是我们用来测试的,不希望它显示在文档里。
  2. 基本上没有任何描述信息来说明这个接口的功能。
  3. 接口的部分参数也没有描述信息,可能会让接口的使用者无法知道其准确含义。
  4. GET /posts/archive/dates/ 这个接口显示的参数是错误的,它不应该接受任何查询参数,接口响应参数也是错误的。
  5. GET /posts/{id}/comments/ 这个接口应该还支持分页查询的参数,但生成的文档中没有列出,接口响应参数也是错误的,正确的应该是一个分页后的评论列表,但文档中是单个评论对象。
  6. GET /search/ 没有列出搜索参数 text。
  7. 多出一个 GET /search/{id}/ 接口,这个接口我们并不需要其被使用,因此也无需在文档列出。

接下来我们就一个个地来解决上面的问题,只需要稍加改变一下 drf-yasg 的默认行为,就能够生成我们预期的文档内容。

隐藏不需要的接口

首先将第 1 点和第 7 点提到的不需要的接口从自动生成的文档中隐藏。

对于 GET /api-version/test/ 这个接口,它对应的视图集是 ApiVersionTestViewSet,给这个视图集添加一个 swagger_schema 类属性,将值设为 None,这样 drf-yasg 就知道忽略这个视图集对应的接口了。

# filename="blog/views.py"class ApiVersionTestViewSet(viewsets.ViewSet):  # pragma: no cover
    swagger_schema = None复制代码

隐藏 GET /search/{id}/ 接口的方式稍微有点不同,因为对应的视图集 PostSearchView 不只这一个接口,上面的处理方式会把整个视图集的接口都隐藏,我们需要想办法隐藏指定 action 对应的接口。

drf-yasg 提供了一个 swagger_auto_schema 装饰器来装饰视图,只需要为装饰器设置 auto_shema=None 就可以让 drf-yasg 忽略掉被装饰的视图,具体用法如下:

# filename="blog/views.py"from django.utils.decorators import method_decoratorfrom drf_yasg.utils import swagger_auto_schema@method_decorator(
    name="retrieve",
    decorator=swagger_auto_schema(
        auto_schema=None,
    ),
)class PostSearchView(HaystackViewSet):
    index_models = [Post]
    serializer_class = PostHaystackSerializer
    throttle_classes = [PostSearchAnonRateThrottle]复制代码

需要隐藏的接口对应 retrieve 这个 action,因此我们装饰的是这个方法。因为 PostSearchView 继承自 HaystackViewSet,在代码中并没有显示地定义 retrieve 这个方法,而是从父类继承而来,所以我们借助 django 提供的辅助函数 method_decorator 非侵入式地为类的某个方法添加装饰器。

现在访问接口文档地址,可以看到不需要的接口已经从文档中隐藏了。

添加接口功能描述信息

接下来解决第 2 个问题,为接口添加必要的功能描述。drf-yasg 支持从视图的 docstring 解析接口对应的描述信息,只要符合指定的格式即可。

先来一个简单例子,为 GET /categories/ 这个接口添加描述信息,找到 CategoryViewSet 视图集,添加格式化的 docstring:

# filename="blog/views.py"class CategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    博客文章分类视图集

    list:
    返回博客文章分类列表
    """复制代码

CategoryViewSet 视图集就一个接口,对应的 action 是 list,因此 docstring 的格式就像上面那样,文档中的效果如下:

Voir la documentation de l'interface de gestion

可以看到接口请求 URL 下方多出了我们写的描述内容。其它一些简单的接口都可以用这种方式来添加功能描述信息,留作练习的内容交给你自己了。

tip 描述的内容还支持 Markdown 格式,这样我们可以根据需要写出格式丰富的内容。

对于稍微复杂一点视图集,例如 PostViewSet,这个视图集含有多个 action 对应多个接口,功能描述信息的格式差不多是一样的,关键点是指明每个 action 对应的内容:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """
    博客文章视图集

    list:
    返回博客文章列表

    retrieve:
    返回博客文章详情

    list_comments:
    返回博客文章下的评论列表

    list_archive_dates:
    返回博客文章归档日期列表
    """复制代码

添加参数说明

接着我们来完善接口的参数说明文档。通过查看自动生成的文档中各个接口的参数,发现主要有这么几个问题:

  • 有些参数没有说明,无法准确知道其含义。
  • 有些接口该有的参数,文档中没有列出。
  • 有些接口不该有的参数,文档中却列出来了。

例如我们可以看到 GET /posts/{id}/ 这个接口的响应参数,其中大部分有中文信息的描述,我们可以推断,这些说明都是 drf-yasg 自动从定义在 Post 模型各字段的 verbose_name 参数的值提取的。其中 toc 和 body_html 因为不是 Post 中定义的字段,所以 drf-yasg 无法知道关于这两个字段的说明。

drf-yasg 是如何知道这个接口会返回哪些响应参数的呢?原理是 drf-yasg 会尝试去解析接口对应的序列化器(Serializer),从序列化器中提取出对应的请求和响应字段(如果序列化器中找不到,它会进一步去序列化器关联的模型中找),因此我们就可以给序列化器中定义的字段添加说明信息。例如我们来给 toc 和 body_html 添加 label 参数:

# filename="blog/views.py"class PostRetrieveSerializer(serializers.ModelSerializer):
    toc = serializers.CharField(label="文章目录")
    body_html = serializers.CharField(label="文章内容")复制代码

访问接口文档地址,找到对应的接口,可以看到文档中这两个字段添加了对应的说明信息,还可以通过 help_text(Model 中的字段也支持这个参数)来添加更为详细的描述,例如:

# filename="blog/serializers.py"class PostRetrieveSerializer(serializers.ModelSerializer):
    toc = serializers.CharField(label="文章目录", help_text="HTML 格式,每个目录条目均由 li 标签包裹。")
    body_html = serializers.CharField(
        label="文章内容", help_text="HTML 格式,从 `body` 字段解析而来。"
    )复制代码

这样两个字段的含义就非常清晰了,效果如下:

Voir la documentation de l'interface de gestion

其它一些没有说明信息的字段都可以根据这种方式来添加,只需要找到文档中的参数在代码中对应的来源字段就可以了。除了在序列化器(Serializer)、模型(Model)里面添加。查询过滤参数也是可以这样设置的,例如先来看一下 GET /posts/ 的参数:

Voir la documentation de l'interface de gestion

可以看到用来过滤文章列表的参数都没有说明,这些字段都定义在 PostFilter 中,我们来改一下代码,添加必要的说明信息后再去文档中看看效果吧!

# filename="blog/filters.py"from .models import Category, Post, Tagclass PostFilter(drf_filters.FilterSet):
    created_year = drf_filters.NumberFilter(
        field_name="created_time", lookup_expr="year", help_text="根据文章发表年份过滤文章列表"
    )
    created_month = drf_filters.NumberFilter(
        field_name="created_time", lookup_expr="month", help_text="根据文章发表月份过滤文章列表"
    )
    category = drf_filters.ModelChoiceFilter(
        queryset=Category.objects.all(),
        help_text="根据分类过滤文章列表",
    )
    tags = drf_filters.ModelMultipleChoiceFilter(
        queryset=Tag.objects.all(),
        help_text="根据标签过滤文章列表",
    )    class Meta:
        model = Post
        fields = ["category", "tags", "created_year", "created_month"]复制代码

接着我们来看 GET /posts/archive/dates/ 和 GET /posts/{id}/comments/ 这两个接口。前者文档中显示了一些错误的参数,后者本应该有分页参数,但是文档却没有列出。

先来看 GET /posts/archive/dates/,它对应的 action 是 list_archive_dates,由于 action 默认会从它所在的视图集中继承一些属性,而 drf-yasg 会从这些属性去解析接口支持的参数,例如视图集设置了 filterset_class = PostFilterpagination_class=PageNumberPagination(虽然不在视图集中显示定义,但在全局进行了配置),在解析 list_archive_dates 的参数时,drf-yasg 错误地解析到了从视图集继承来的 PostFilterPageNumberPagination,所以就把这两个类中定义的参数也包含进文档了。

知道了原因,解决方法也就有了,在 list_archive_dates action 中把这两个属性设为 None,覆盖掉视图集中的默认设置:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):  @action(
        # ...
        filter_backends=None, # 将 filter_backends 设为 None,filterset_class 也就不起作用了。
        pagination_class=None,
    )    def list_archive_dates(self, request, *args, **kwargs):
        # ...复制代码

再来看看这个接口,就没有那些错误的参数了。

接着处理 GET /posts/{id}/comments/ 接口,我们需要文档列出分页参数。这个接口对应的 action 是 list_comment。从上面的分析来看,这个 action 明明已经指定了 pagination_class=LimitOffsetPagination,为什么 drf-yasg 无法自动检测到分页参数呢?原因是这个 action 设置了 detail=True。当 detial=True 时,drf-yasg 会将这个 action 对应的接口看做获取单个资源的接口,因此它认为分页是不需要的。但实际上我们对这个接口进行了定制,它返回的其实是评论列表。解决办法是应该告诉 drf-yasg,这个接口返回的是列表结果,请去解析列表接口相关的一些参数:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):    @action(
        methods=["GET"],
        detail=True,        # ...
        suffix="List",  # 将这个 action 返回的结果标记为列表,否则 drf-yasg 会根据 detail=True 误判为这是返回单个资源的接口
        pagination_class=LimitOffsetPagination,
        serializer_class=CommentSerializer,
    )    def list_comments(self, request, *args, **kwargs):
        # ...复制代码

但是 drf-yasg 还是不够聪明,当它去解析列表接口可能的参数时,顺便又把 PostFilter 中的字段也一并解析了,这是用来过滤博客文章的,显然不能用于过滤评论列表,我们需要将这些无关参数移除,解决方法在处理 GET /posts/archive/dates/ 接口时就讲过了,把 filter_backends 设置成 None 就可以了。

更正错误的响应参数

仔细看生成的接口文档,发现有 2 个接口的返回内容是错误的。

一是 GET /posts/{id}/comments/,最初我们发现这个接口文档的响应是一个单一的评论对象,原因我们上面也分析了,drf-yasg 根据 detail=True 误地将其作为返回单一资源的接口处理了。随着为其添加更多信息,告诉 drf-yasg 这是一个返回资源列表的接口,问题也就顺便解决了。

二是 GET /posts/archive/dates/,这个接口的返回内容应该是一个日期列表,但是文档中显示的竟然是博客文章列表。drf-yasg 推断的响应类型是正确的,但内容不对。原因也很明显,这个接口对应的 action 是 list_archive_dates,drf-yasg 在这个 action 中没有找到解析响应结果的序列化器(Serializer),所以它跑去视图集 PostViewSet 中去找了,结果找到了 PostListSerializer,然后把这个当成了接口返回的内容进行解析了。

由于这个接口返回的仅仅是一个简单的日期列表,并不涉及到序列化器,因此这里我们不使用指定 serializer_class 属性值的方式,而是使用 swagger_auto_schema 装饰器,直接告诉 drf-yasg 接口返回的响应:

# filename="blog/views.py"class PostViewSet(
    mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):        @swagger_auto_schema(responses={200: "归档日期列表,时间倒序排列。例如:[&#39;2020-08&#39;, &#39;2020-06&#39;]"})    @action(
        methods=["GET"],
        detail=False,
        url_path="archive/dates",
        url_name="archive-date",
        filter_backends=None,
        pagination_class=None,
    )    def list_archive_dates(self, request, *args, **kwargs):
        # ...复制代码

responses 参数的值是一个字典,字典的键是 HTTP 响应码,值可以是一个序列化器,这样 drf-yasg 会拿这个序列化器去解析接口响应的参数;也可以是一个字符串,drf-yasg 会把字符串直接当做接口响应结果写入文档中。看看修改后的效果:

Voir la documentation de l'interface de gestion

至此,我们就有了一套比较完善的博客接口文档了,而且大部分内容均由 drf-yasg 为我们自动生成,省去了不少手写文档的麻烦。

小贴士:

drf-yasg 的官方文档对于这个库的使用方法写的不是很清晰,这篇文章中列出的一些用法都是从源码中看出来的。如果你在使用过程中遇到了问题,首先尝试分析问题的原因,然后顺藤摸瓜去找到相关的源码,看看库的内部是如何处理你所遇到的问题的,这样就可以针对性地给出解决方案了,这篇教程中列出的很多问题以及最后给出的解决方案,都是使用的这种方式。

想了解更多编程学习,敬请关注php培训栏目!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer