相干学习保举:python教程
年夜少数状况下,开发的接口都没有是给开发这个接口的人用的,以是假如不接口文档,他人就无奈有哪些接口能够挪用,即便晓得了接口的 URL,也很难晓得接口需求哪些参数,即便晓得了这些参数,也可能无奈了解这些参数的含意。因而接口文档应该是名目必不成少的设置装备摆设。
编写接口文档有不少种形式,最为简略间接的形式就是关上一个记事本或许 word 文档,将接口的具体信息以及用法写上去,他人就能够参考这个文档来挪用接口。这样做尽管简略,但弊病也很显著:一是需求写年夜量的形容文字,十分单调,但其实这些信息正在代码中已有表现,有点像是应用天然言语又把代码写了一遍;二是一旦接口有了更新,就必需手动同步更新接口文档,开发职员很容易搞忘这件事,招致接口文档的内容以及接口的实际性能纷歧致。
由于不少接口的信息其真实代码中已有表现,人们天然而然就想到是否间接从写好的代码中主动提取相干信息来天生文档,这样改了代码,接口文档也会主动更新,下面说的两个成绩就均可以处理了。
当然写接口文档没有是搞文学创作,为了间接从写好的代码中主动提守信息来天生文档,就必需要有一套规范的文档格局,不然对象无奈晓得要从代码中提掏出哪些信息,信息提取之后,也没有晓得该若何组织这些信息。
通过各人的致力,如今曾经有了不少成熟的接口文档规范以及天生对象,此中 OpenAPI Specification 就是一个被宽泛接纳以及应用的规范,咱们博客接口应用的文档主动化对象,也会基于 OpenAPI 规范从代码中提取文档信息,而后组织为 OpenAPI 的规范格局。
小贴士:
各人更为相熟的,以及 OpenAPI 相干的一个名词是 swagger。Swagger 提供一系列收费开源的 OpenAPI 相干的对象,他们面前的公司是 SMARTBEAR,号称 code quality tools 开刊行业的辅导者。
OpenAPI 引见
接口文档没有是文学作品,它所需求的内容根本都是固定的。例如对一个 RESTful 格调的接口来讲,只要要晓得如下这些要害的信息就足够实现对它的挪用了。反过去,这些信息也就能够界说一个完好的 RESTful 格调的接口:
- 申请的 HTTP 办法以及 URL。
- 接纳的参数(包罗 URL 中的门路参数、查问参数;HTTP 申请头的参数;HTTP 申请体等参数)。
- 接口前往的内容。
OpenAPI 对以上信息进行了规范化,从而提出了 OpenAPI specification,只需文档内容合乎这个规范,OpenAPI 对象就能够对它进行解决,例如可视化文档对象就能够读取文档内容天生 HTML 格局的文档。
留意:
OpenAPI specification 今朝最新版本是 3,但今朝年夜局部对象对 2 的支持最佳,教程中应用的库仅支持 2。
drf-yasg
drf-yasg 是一个 django 的第三方使用,它能够从 django-rest-framework 框架编写的代码中主动提取接口信息来天生合乎 OpenAPI 规范的文档。咱们将应用它来天生博客使用的接口文档。
第一步当然是装置 drf-yasg,进入名目根目次,运转饬令 :
Co妹妹and Tab
Linux/macOS $ pipenv install drf-yasg复制代码
Windows ...\> pipenv install drf-yasg复制代码
而后将 drf-yasg 增加到 INSTALLED_APPS
设置装备摆设项中:
# filename="blogproject/settings/co妹妹on.py"INSTALLED_APPS = [ # 其它已增加的使用... "pure_pagination", # 分页 "haystack", # 搜寻 "drf_yasg", # 文档]复制代码
接着应用 drf_yasg 提供的函数来创立一个 django 视图,这个视图将前往 HTML 格局的文档内容,这样咱们就能够间接正在阅读器查看到博客的接口文档:
# 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"), ]复制代码
只要要应用 get_schema_view
就能够天生一个文档视图,而后咱们将这个视图函数映照到了 4 个 URL。
如今进入名目根目次,启动开发效劳器:
Co妹妹and Tab
Linux/macOS $ pipenv run python manage.py runserver复制代码
Windows ...\> pipenv run python manage.py runserver复制代码
而后拜访 http://127.0.0.1:8000/swagger/ 或许 http://127.0.0.1:8000/redoc/,你就能够看到 drf-yasg 主动天生的 HTML 格局的接口文档了。假如拜访 http://127.0.0.1:8000/swagger.json 或许 http://127.0.0.1:8000/swagger.yaml 就能够看到原始的 OpenAPI 规范文档,swagger 以及 redoc 都是基于这个规范文档来天生可视化的 UI 界面的。
欠缺文档
drf-yasg 究竟结果没有是应用人工智能开发的,即便是应用人工智能,也很难做到 100% 的正确,究竟结果由人类写的代码多是变幻无穷的,对象无奈意料到一切可能的状况,一旦它遇到无奈解决之处,主动天生的文档就可能犯错,或许天生的内容没有合乎咱们的预期。
咱们无妨拜访 http://127.0.0.1:8000/swagger/ 先来看看没做任何定制化以前天生的成果。能够看到内容大要上是正确的,接口根本上都列举了进去,然而细心反省各个接口的内容,就会发现一些成绩:
- GET /api-version/test/ 这个接口是咱们用来测试的,没有心愿它显示正在文档里。
- 根本上不任何形容信息来讲明这个接口的性能。
- 接口的局部参数也不形容信息,可能会让接口的应用者无奈晓得其精确含意。
- GET /posts/archive/dates/ 这个接口显示的参数是谬误的,它不该该承受任何查问参数,接口呼应参数也是谬误的。
- GET /posts/{id}/co妹妹ents/ 这个接口应该还支持分页查问的参数,但天生的文档中不列出,接口呼应参数也是谬误的,正确的应该是一个分页后的评论列表,但文档中是单个评论工具。
- GET /search/ 不列出搜寻参数 text。
- 多出一个 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 的格局就像下面那样,文档中的成果以下:
能够看到接口申请 URL 下方多出了咱们写的形容内容。其它一些简略的接口均可以用这类形式来增加性能形容信息,留作操练的内容交给你本人了。
tip 形容的内容还支持 Markdown 格局,这样咱们能够依据需求写出格局丰厚的内容。
关于略微复杂一点视图集,例如 PostViewSet
,这个视图集含有多个 action 对应多个接口,性能形容信息的格局差没有可能是同样的,要害点是指明每一个 action 对应的内容:
# filename="blog/views.py"class PostViewSet( mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ 博客文章视图集 list: 前往博客文章列表 retrieve: 前往博客文章概况 list_co妹妹ents: 前往博客文章下的评论列表 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` 字段解析而来。" )复制代码
这样两个字段的含意就十分明晰了,成果以下:
其它一些不阐明信息的字段均可以依据这类形式来增加,只要要找到文档中的参数正在代码中对应的起源字段就能够了。除了了正在序列化器(Serializer)、模子(Model)外面增加。查问过滤参数也是能够这样设置的,例如先来看一下 GET /posts/ 的参数:
能够看到用来过滤文章列表的参数都不阐明,这些字段都界说正在 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}/co妹妹ents/ 这两个接口。前者文档中显示了一些谬误的参数,后者本应该有分页参数,然而文档却不列出。
先来看 GET /posts/archive/dates/,它对应的 action 是 list_archive_dates
,因为 action 默许会从它所正在的视图集中承继一些属性,而 drf-yasg 会从这些属性去解析接口支持的参数,例如视图集设置了 filterset_class = PostFilter
以及 pagination_class=PageNumberPagination
(尽管没有正在视图集中显示界说,但正在全局进行了设置装备摆设),正在解析 list_archive_dates
的参数时,drf-yasg 谬误地解析到了从视图集承继来的 PostFilter
以及 PageNumberPagination
,以是就把这两个类中界说的参数也蕴含进文档了。
晓得了缘由,处理办法也就有了,正在 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}/co妹妹ents/ 接口,咱们需求文档列出分页参数。这个接口对应的 action 是 list_co妹妹ent
。从下面的剖析来看,这个 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=Co妹妹entSerializer, ) def list_co妹妹ents(self, request, *args, **kwargs): # ...复制代码
然而 drf-yasg 仍是不敷聪慧,当它去解析列表接口可能的参数时,趁便又把 PostFilter
中的字段也一并解析了,这是用来过滤博客文章的,显然不克不及用于过滤评论列表,咱们需求将这些有关参数移除了,处理办法正在解决 GET /posts/archive/dates/ 接口时就讲过了,把 filter_backends
设置成 None 就能够了。
更正谬误的呼应参数
细心看天生的接口文档,发现有 2 个接口的前往内容是谬误的。
一是 GET /posts/{id}/co妹妹ents/,最后咱们发现这个接口文档的呼应是一个繁多的评论工具,缘由咱们下面也剖析了,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: "归档日期列表,工夫倒序陈列。例如:['2020-08', '2020-06']"}) @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 会把字符串间接当作接口呼应后果写入文档中。看看修正后的成果:
至此,咱们就有了一套比拟欠缺的博客接口文档了,并且年夜局部内容均由 drf-yasg 为咱们主动天生,省去了很多手写文档的费事。
小贴士:
drf-yasg 的民间文档关于这个库的应用办法写的没有是很明晰,这篇文章中列出的一些用法都是从源码中看进去的。假如你正在应用进程中遇到了成绩,起首测验考试剖析成绩的缘由,而后顺藤摸瓜去找到相干的源码,看看库的外部是若何解决你所遇到的成绩的,这样就能够针对性地给出处理计划了,这篇教程中列出的不少成绩和最初给出的处理计划,都是应用的这类形式。
想理解更多编程学习,敬请存眷php培训栏目!
以上就是看透 治理接口文档的具体内容,更多请存眷资源魔其它相干文章!
标签: python教程 python编程 python使用问题 接口文档
抱歉,评论功能暂时关闭!