站長資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        看透 管理接口文檔

        看透 管理接口文檔

        相關(guān)學習推薦:python教程

        大多數(shù)情況下,開發(fā)的接口都不是給開發(fā)這個接口的人用的,所以如果沒有接口文檔,別人就無法有哪些接口可以調(diào)用,即使知道了接口的 URL,也很難知道接口需要哪些參數(shù),即使知道了這些參數(shù),也可能無法理解這些參數(shù)的含義。因此接口文檔應該是項目必不可少的配置。

        編寫接口文檔有很多種方式,最為簡單直接的方式就是打開一個記事本或者 word 文檔,將接口的詳細信息和用法寫下來,別人就可以參考這個文檔來調(diào)用接口。這樣做雖然簡單,但弊端也很明顯:一是需要寫大量的描述文字,非常枯燥,但其實這些信息在代碼中已有體現(xiàn),有點像是使用自然語言又把代碼寫了一遍;二是一旦接口有了更新,就必須手動同步更新接口文檔,開發(fā)人員很容易搞忘這件事,導致接口文檔的內(nèi)容和接口的實際功能不一致。

        因為很多接口的信息其實在代碼中已有體現(xiàn),人們自然而然就想到能否直接從寫好的代碼中自動提取相關(guān)信息來生成文檔,這樣改了代碼,接口文檔也會自動更新,上面說的兩個問題就都可以解決了。

        當然寫接口文檔不是搞文學創(chuàng)作,為了直接從寫好的代碼中自動提取信息來生成文檔,就必須要有一套標準的文檔格式,否則工具無法知道要從代碼中提取出哪些信息,信息提取之后,也不知道該如何組織這些信息。

        經(jīng)過大家的努力,現(xiàn)在已經(jīng)有了很多成熟的接口文檔標準和生成工具,其中 OpenAPI Specification 就是一個被廣泛接收和使用的標準,我們博客接口使用的文檔自動化工具,也會基于 OpenAPI 標準從代碼中提取文檔信息,然后組織為 OpenAPI 的標準格式。

        小貼士:

        大家更為熟悉的,和 OpenAPI 相關(guān)的一個名詞是 swagger。Swagger 提供一系列免費開源的 OpenAPI 相關(guān)的工具,他們背后的公司是 SMARTBEAR,號稱 code quality tools 開發(fā)行業(yè)的領(lǐng)導者。

        OpenAPI 介紹

        接口文檔不是文學作品,它所需要的內(nèi)容基本都是固定的。例如對一個 RESTful 風格的接口來說,只需要知道以下這些關(guān)鍵的信息就足夠完成對它的調(diào)用了。反過來,這些信息也就可以定義一個完整的 RESTful 風格的接口:

        • 請求的 HTTP 方法和 URL。
        • 接收的參數(shù)(包括 URL 中的路徑參數(shù)、查詢參數(shù);HTTP 請求頭的參數(shù);HTTP 請求體等參數(shù))。
        • 接口返回的內(nèi)容。

        OpenAPI 對以上信息進行了標準化,從而提出了 OpenAPI specification,只要文檔內(nèi)容符合這個標準,OpenAPI 工具就可以對它進行處理,例如可視化文檔工具就可以讀取文檔內(nèi)容生成 HTML 格式的文檔。

        注意:

        OpenAPI specification 目前最新版本是 3,但目前大部分工具對 2 的支持最好,教程中使用的庫僅支持 2。

        drf-yasg

        drf-yasg 是一個 django 的第三方應用,它可以從 django-rest-framework 框架編寫的代碼中自動提取接口信息來生成符合 OpenAPI 標準的文檔。我們將使用它來生成博客應用的接口文檔。

        第一步當然是安裝 drf-yasg,進入項目根目錄,運行命令 :

        Command Tab

        Linux/macOS $ pipenv install drf-yasg復制代碼
        Windows ...> pipenv install drf-yasg復制代碼

        然后將 drf-yasg 添加到 INSTALLED_APPS 配置項中:

        # filename="blogproject/settings/common.py"INSTALLED_APPS = [    # 其它已添加的應用...         "pure_pagination",  # 分頁     "haystack",  # 搜索     "drf_yasg", # 文檔]復制代碼

        接著使用 drf_yasg 提供的函數(shù)來創(chuàng)建一個 django 視圖,這個視圖將返回 HTML 格式的文檔內(nèi)容,這樣我們就可以直接在瀏覽器查看到博客的接口文檔:

        # 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 就可以生成一個文檔視圖,然后我們將這個視圖函數(shù)映射到了 4 個 URL。

        現(xiàn)在進入項目根目錄,啟動開發(fā)服務器:

        Command 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 畢竟不是使用人工智能開發(fā)的,即使是使用人工智能,也很難做到 100% 的正確,畢竟由人類寫的代碼可能是千變?nèi)f化的,工具無法預料到所有可能的情況,一旦它遇到無法處理的地方,自動生成的文檔就可能出錯,或者生成的內(nèi)容不符合我們的預期。

        我們不妨訪問 http://127.0.0.1:8000/swagger/ 先來看看沒做任何定制化之前生成的效果。可以看到內(nèi)容大體上是正確的,接口基本上都羅列了出來,但是仔細檢查各個接口的內(nèi)容,就會發(fā)現(xiàn)一些問題:

        1. GET /api-version/test/ 這個接口是我們用來測試的,不希望它顯示在文檔里。
        2. 基本上沒有任何描述信息來說明這個接口的功能。
        3. 接口的部分參數(shù)也沒有描述信息,可能會讓接口的使用者無法知道其準確含義。
        4. GET /posts/archive/dates/ 這個接口顯示的參數(shù)是錯誤的,它不應該接受任何查詢參數(shù),接口響應參數(shù)也是錯誤的。
        5. GET /posts/{id}/comments/ 這個接口應該還支持分頁查詢的參數(shù),但生成的文檔中沒有列出,接口響應參數(shù)也是錯誤的,正確的應該是一個分頁后的評論列表,但文檔中是單個評論對象。
        6. GET /search/ 沒有列出搜索參數(shù) text。
        7. 多出一個 GET /search/{id}/ 接口,這個接口我們并不需要其被使用,因此也無需在文檔列出。

        接下來我們就一個個地來解決上面的問題,只需要稍加改變一下 drf-yasg 的默認行為,就能夠生成我們預期的文檔內(nèi)容。

        隱藏不需要的接口

        首先將第 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 提供的輔助函數(shù) method_decorator 非侵入式地為類的某個方法添加裝飾器。

        現(xiàn)在訪問接口文檔地址,可以看到不需要的接口已經(jīng)從文檔中隱藏了。

        添加接口功能描述信息

        接下來解決第 2 個問題,為接口添加必要的功能描述。drf-yasg 支持從視圖的 docstring 解析接口對應的描述信息,只要符合指定的格式即可。

        先來一個簡單例子,為 GET /categories/ 這個接口添加描述信息,找到 CategoryViewSet 視圖集,添加格式化的 docstring:

        # filename="blog/views.py"class CategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):     """     博客文章分類視圖集      list:     返回博客文章分類列表     """復制代碼

        CategoryViewSet 視圖集就一個接口,對應的 action 是 list,因此 docstring 的格式就像上面那樣,文檔中的效果如下:

        看透 管理接口文檔

        可以看到接口請求 URL 下方多出了我們寫的描述內(nèi)容。其它一些簡單的接口都可以用這種方式來添加功能描述信息,留作練習的內(nèi)容交給你自己了。

        tip 描述的內(nèi)容還支持 Markdown 格式,這樣我們可以根據(jù)需要寫出格式豐富的內(nèi)容。

        對于稍微復雜一點視圖集,例如 PostViewSet,這個視圖集含有多個 action 對應多個接口,功能描述信息的格式差不多是一樣的,關(guān)鍵點是指明每個 action 對應的內(nèi)容:

        # filename="blog/views.py"class PostViewSet(     mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):     """     博客文章視圖集      list:     返回博客文章列表      retrieve:     返回博客文章詳情      list_comments:     返回博客文章下的評論列表      list_archive_dates:     返回博客文章歸檔日期列表     """復制代碼

        添加參數(shù)說明

        接著我們來完善接口的參數(shù)說明文檔。通過查看自動生成的文檔中各個接口的參數(shù),發(fā)現(xiàn)主要有這么幾個問題:

        • 有些參數(shù)沒有說明,無法準確知道其含義。
        • 有些接口該有的參數(shù),文檔中沒有列出。
        • 有些接口不該有的參數(shù),文檔中卻列出來了。

        例如我們可以看到 GET /posts/{id}/ 這個接口的響應參數(shù),其中大部分有中文信息的描述,我們可以推斷,這些說明都是 drf-yasg 自動從定義在 Post 模型各字段的 verbose_name 參數(shù)的值提取的。其中 toc 和 body_html 因為不是 Post 中定義的字段,所以 drf-yasg 無法知道關(guān)于這兩個字段的說明。

        drf-yasg 是如何知道這個接口會返回哪些響應參數(shù)的呢?原理是 drf-yasg 會嘗試去解析接口對應的序列化器(Serializer),從序列化器中提取出對應的請求和響應字段(如果序列化器中找不到,它會進一步去序列化器關(guān)聯(lián)的模型中找),因此我們就可以給序列化器中定義的字段添加說明信息。例如我們來給 toc 和 body_html 添加 label 參數(shù):

        # filename="blog/views.py"class PostRetrieveSerializer(serializers.ModelSerializer):     toc = serializers.CharField(label="文章目錄")     body_html = serializers.CharField(label="文章內(nèi)容")復制代碼

        訪問接口文檔地址,找到對應的接口,可以看到文檔中這兩個字段添加了對應的說明信息,還可以通過 help_text(Model 中的字段也支持這個參數(shù))來添加更為詳細的描述,例如:

        # filename="blog/serializers.py"class PostRetrieveSerializer(serializers.ModelSerializer):     toc = serializers.CharField(label="文章目錄", help_text="HTML 格式,每個目錄條目均由 li 標簽包裹。")     body_html = serializers.CharField(         label="文章內(nèi)容", help_text="HTML 格式,從 `body` 字段解析而來。"     )復制代碼

        這樣兩個字段的含義就非常清晰了,效果如下:

        看透 管理接口文檔

        其它一些沒有說明信息的字段都可以根據(jù)這種方式來添加,只需要找到文檔中的參數(shù)在代碼中對應的來源字段就可以了。除了在序列化器(Serializer)、模型(Model)里面添加。查詢過濾參數(shù)也是可以這樣設置的,例如先來看一下 GET /posts/ 的參數(shù):

        看透 管理接口文檔

        可以看到用來過濾文章列表的參數(shù)都沒有說明,這些字段都定義在 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="根據(jù)文章發(fā)表年份過濾文章列表"     )     created_month = drf_filters.NumberFilter(         field_name="created_time", lookup_expr="month", help_text="根據(jù)文章發(fā)表月份過濾文章列表"     )     category = drf_filters.ModelChoiceFilter(         queryset=Category.objects.all(),         help_text="根據(jù)分類過濾文章列表",     )     tags = drf_filters.ModelMultipleChoiceFilter(         queryset=Tag.objects.all(),         help_text="根據(jù)標簽過濾文章列表",     )    class Meta:         model = Post         fields = ["category", "tags", "created_year", "created_month"]復制代碼

        接著我們來看 GET /posts/archive/dates/ 和 GET /posts/{id}/comments/ 這兩個接口。前者文檔中顯示了一些錯誤的參數(shù),后者本應該有分頁參數(shù),但是文檔卻沒有列出。

        先來看 GET /posts/archive/dates/,它對應的 action 是 list_archive_dates,由于 action 默認會從它所在的視圖集中繼承一些屬性,而 drf-yasg 會從這些屬性去解析接口支持的參數(shù),例如視圖集設置了 filterset_class = PostFilterpagination_class=PageNumberPagination(雖然不在視圖集中顯示定義,但在全局進行了配置),在解析 list_archive_dates 的參數(shù)時,drf-yasg 錯誤地解析到了從視圖集繼承來的 PostFilterPageNumberPagination,所以就把這兩個類中定義的參數(shù)也包含進文檔了。

        知道了原因,解決方法也就有了,在 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):         # ...復制代碼

        再來看看這個接口,就沒有那些錯誤的參數(shù)了。

        接著處理 GET /posts/{id}/comments/ 接口,我們需要文檔列出分頁參數(shù)。這個接口對應的 action 是 list_comment。從上面的分析來看,這個 action 明明已經(jīng)指定了 pagination_class=LimitOffsetPagination,為什么 drf-yasg 無法自動檢測到分頁參數(shù)呢?原因是這個 action 設置了 detail=True。當 detial=True 時,drf-yasg 會將這個 action 對應的接口看做獲取單個資源的接口,因此它認為分頁是不需要的。但實際上我們對這個接口進行了定制,它返回的其實是評論列表。解決辦法是應該告訴 drf-yasg,這個接口返回的是列表結(jié)果,請去解析列表接口相關(guān)的一些參數(shù):

        # filename="blog/views.py"class PostViewSet(     mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):    @action(         methods=["GET"],         detail=True,        # ...         suffix="List",  # 將這個 action 返回的結(jié)果標記為列表,否則 drf-yasg 會根據(jù) detail=True 誤判為這是返回單個資源的接口         pagination_class=LimitOffsetPagination,         serializer_class=CommentSerializer,     )    def list_comments(self, request, *args, **kwargs):         # ...復制代碼

        但是 drf-yasg 還是不夠聰明,當它去解析列表接口可能的參數(shù)時,順便又把 PostFilter 中的字段也一并解析了,這是用來過濾博客文章的,顯然不能用于過濾評論列表,我們需要將這些無關(guān)參數(shù)移除,解決方法在處理 GET /posts/archive/dates/ 接口時就講過了,把 filter_backends 設置成 None 就可以了。

        更正錯誤的響應參數(shù)

        仔細看生成的接口文檔,發(fā)現(xiàn)有 2 個接口的返回內(nèi)容是錯誤的。

        一是 GET /posts/{id}/comments/,最初我們發(fā)現(xiàn)這個接口文檔的響應是一個單一的評論對象,原因我們上面也分析了,drf-yasg 根據(jù) detail=True 誤地將其作為返回單一資源的接口處理了。隨著為其添加

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
        主站蜘蛛池模板: 国产精品免费无遮挡无码永久视频 | 亚洲国产av无码精品| 色播精品免费小视频| 免费欧美精品a在线| 国内精品久久久久久久涩爱 | 亚洲国产精品久久久久| 老汉精品免费AV在线播放| HEYZO无码综合国产精品| 亚洲国产精品久久久久久| 精品黑人一区二区三区| 中文字幕精品一区二区日本| 日韩一区二区三区精品| 精品国偷自产在线| 亚洲精品美女久久777777| 国产91久久精品一区二区| 国产午夜精品久久久久九九电影 | 完整观看高清秒播国内外精品资源| 97国产视频精品| 久久国产免费观看精品| 久99久无码精品视频免费播放| 日韩精品无码专区免费播放| 欧美精品国产精品| 97久久精品午夜一区二区| 国产美女精品一区二区三区| 无码精品日韩中文字幕| 亚洲日韩精品无码一区二区三区| 99久久99这里只有免费费精品| 午夜欧美精品久久久久久久| 亚洲精品专区在线观看| 欧美精品在线一区| 欧美精品福利视频| 91精品福利在线观看| 中文字幕亚洲精品资源网| 日本精品不卡视频| 99久久人人爽亚洲精品美女| 亚洲精品中文字幕乱码三区| 亚洲精品国产精品乱码不卡| 一本久久精品一区二区| 色婷婷在线精品国自产拍| 国产三级精品三级在线专区1| 国产成人精品午夜福利|