Swagger使用初探

簡(jiǎn)介

Swagger是什么?在解答這個(gè)問題之前悴晰,我們先來看看開發(fā)Restful API過程中會(huì)遇到什么問題慢睡。我們?nèi)绾稳ピO(shè)計(jì)和定義API接口?如何寫接口文檔膨疏?是否可以自動(dòng)生成接口文檔一睁,或者設(shè)計(jì)好API之后自動(dòng)生成接口代碼钻弄?如果有那么一個(gè)工具可以幫助我們實(shí)現(xiàn)上述功能佃却,是否感覺很棒。是的窘俺,Swagger就是干這個(gè)的饲帅,而且通過Swagger生成的接口文檔不僅非常漂亮,還能實(shí)現(xiàn)交互測(cè)試的功能瘤泪。
Swagger實(shí)際上是通過一系列工具來實(shí)現(xiàn)這些功能的灶泵。其主要工具如下:

  • Swagger-editor : 一個(gè)用于編輯API文檔的工具
  • Swagger-ui: 用于解析editor生成的json文件,并生成對(duì)應(yīng)的API文檔的頁面对途,并可以展示頁面的web應(yīng)用
  • Swagger-core: Swagger的Java/Scala實(shí)現(xiàn)赦邻,并已集成 JAX-RS (Jersey, Resteasy, CXF...), Servlets與Play Framework (其實(shí)不懂,有明白的網(wǎng)友歡迎留言)
  • Swagger-codegen: 用于自動(dòng)生成客戶端和服務(wù)器端的代碼

我目前使用的主要是swagger-editor和swagger-ui实檀,用于生成API文檔惶洲。下面先介紹這兩個(gè)工具按声。

Swagger-Editor

swagger-editor主要用于在設(shè)計(jì)和定義restful api的時(shí)候使用。我們通過編輯YAML配置文件恬吕,從而可以自動(dòng)顯示出API文檔签则,從而允許我們先將接口定義清楚。

Swagger-Editor安裝

  1. 下載Swagger-Editor铐料。直接下載zip文件地址并解壓
  2. 下載并且安裝node.js
  3. npm install -g http-server
  4. 進(jìn)入swagger-editor文件夾渐裂。運(yùn)行http-server命令。
  5. 在瀏覽器中輸入http://127.0.0.1:8080即可看到Swagger-Editor的界面

YAML語言

關(guān)于YAML語言可以參考阮一峰老師的YAML 語言教程钠惩。簡(jiǎn)單來說柒凉,我們可以通過YAML來實(shí)現(xiàn)某種類似于json的數(shù)據(jù)表達(dá)和描述的方式。但是它跟json相比較而言篓跛,可以有更豐富的信息表達(dá)扛拨,比如可以描述數(shù)據(jù)的類型,可以添加更多的文檔相關(guān)的信息(這一點(diǎn)類似于xml举塔,但是yaml要比xml簡(jiǎn)潔的多绑警,當(dāng)然代價(jià)是不能像xml那樣可以通過dtd文件來驗(yàn)證其正確性)。另外央渣,大部分語言都有YAML語言的相關(guān)實(shí)現(xiàn)计盒,比如在Python中我們通過安裝pyyaml或者ruamel.yaml(支持yaml1.2)來實(shí)現(xiàn)對(duì)YAML文檔的讀寫。

OpenAPI Specification

YAML只是一種數(shù)據(jù)表示芽丹,我們還必須通過一定的規(guī)范才能描述API接口文檔(比如定義path用來描述路徑)北启,而這個(gè)規(guī)范就是OpenAPI Specification。目前最新的版本是3.x版本(文檔開頭會(huì)是openapi: 3.0.0)拔第,而在Swagger的很多例子當(dāng)中我們看到的是2.0的版本(也就是通常在文件開頭的swagger: 2.0)咕村。這一點(diǎn)是需要注意的,因?yàn)椴煌陌姹镜膕pec蚊俺,其語法并不相同懈涛,如果搞混就會(huì)報(bào)語法錯(cuò)誤。

OpenAPI Spec文檔可以參考其github地址泳猬。我們以3.0版本為例批钠,先上一個(gè)例子:

# 文本開頭必須先定義openapi版本,必填項(xiàng)
openapi: 3.0.0

# 文檔的meta data得封,顯示文檔的一些基本信息埋心,必填項(xiàng)
info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.1.9

# 定義server相關(guān)信息,非必填
servers:
  - url: http://api.example.com/v1
    description: Optional server description, e.g. Main (production) server
  - url: http://staging-api.example.com
    description: Optional server description, e.g. Internal staging server for testing

# API的具體描述忙上,必填項(xiàng)
paths:
  /users:  # api path
    get:  # api method
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML.
      responses:  # define response
        '200':    # status code
          description: A JSON array of user names
          content:
            application/json:
              schema: 
                type: array
                items: 
                  type: string
  /user/{userId}:
    get:
      summary: Returns a user by ID.
      parameters:  # 定義參數(shù)
        - name: userId
          in: path
          required: true
          description: Parameter description in CommonMark or HTML.
          schema:
            type : integer
            format: int64
            minimum: 1
      responses: 
        '200':
          description: OK

對(duì)照上邊的例子和下表拷呆,我們可以看到OpenAPI spec是如何定義一個(gè)接口的。此種定義方式非常細(xì)致和繁瑣,這主要是因?yàn)镾wagger需要根據(jù)這些細(xì)致地描述來生成相對(duì)應(yīng)的代碼茬斧,所以就有必要將所有的細(xì)節(jié)都描述清楚箫柳。

Field Name Type Description
openapi string REQUIRED. This string MUST be the semantic version number of the OpenAPI Specification version that the OpenAPI document uses. The openapi field SHOULD be used by tooling specifications and clients to interpret the OpenAPI document. This is not related to the API info.version string.
info Info Object REQUIRED. Provides metadata about the API. The metadata MAY be used by tooling as required.
servers [Server Object] An array of Server Objects, which provide connectivity information to a target server. If the servers property is not provided, or is an empty array, the default value would be a Server Object with a url value of /.
paths Paths Object REQUIRED. The available paths and operations for the API.
components Components Object An element to hold various schemas for the specification.
security [Security Requirement Object] A declaration of which security mechanisms can be used across the API. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. Individual operations can override this definition.
tags [Tag Object] A list of tags used by the specification with additional metadata. The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used by the Operation Object must be declared. The tags that are not declared MAY be organized randomly or based on the tools' logic. Each tag name in the list MUST be unique.
externalDocs External Documentation Object Additional external documentation.

通過Swagger-Editor我們可以編輯YAML,同時(shí)直接在右端顯示相應(yīng)的API文檔啥供,如下圖:


swagger-editor

通過[File -> Convert and save as JSON], 我們可以將該YAML轉(zhuǎn)換成json文件悯恍,而該json文件可以通過Swagger-UI來解析并展示成API文檔,同時(shí)伙狐,通過Swagger-UI我們還可以執(zhí)行相應(yīng)的http request測(cè)試涮毫。

Swagger-UI

Swagger-UI安裝

  1. 下載Swagger-UI。直接下載zip文件地址并解壓
  2. 下載并且安裝node.js
  3. npm install -g http-server
  4. 進(jìn)入swagger-editor文件夾贷屎。運(yùn)行http-server -p 8081命令罢防。
  5. 在瀏覽器中輸入http://127.0.0.1:8081即可看到Swagger-UI展示的界面

配置

  1. 首先將Swagger-Editor生成的json文件拷貝到swagger-ui主目錄下的dist文件夾
  2. 修改index.html中的url,假設(shè)你的json文件名為swagger.json唉侄,那么修改url如下:
 <script>
    window.onload = function() {
      // Begin Swagger UI call region
      const ui = SwaggerUIBundle({
        # 主要是修改這里的url咒吐,以對(duì)應(yīng)你在dist目錄下的json文件
        url: "http://127.0.0.1:8081/dist/swagger.json",
        dom_id: '#swagger-ui',
        deepLinking: true,
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      })
      // End Swagger UI call region

      window.ui = ui
    }
  </script>
  1. 重新啟動(dòng)Swagger-UI
# 注意端口必須要與url中設(shè)定的端口一致,否則會(huì)有跨域問題
http-server -p 8081

這時(shí)属划,就可以看到Swagger-UI解析生成的API文檔了

通過Nginx展示靜態(tài)頁面

當(dāng)我們需要對(duì)外部展示API文檔的時(shí)候恬叹,我們可以通過redoc-cli來生成靜態(tài)的html頁面。步驟如下:

  1. npm install -g redoc-cli
  2. 有時(shí)redoc-cli無法直接使用同眯, 需要安裝npx.
    npm install -g npx
    注意: 有些系統(tǒng)(比如Ubuntu)绽昼,其安裝位置為/opt目錄下,我們需要將其添加到path當(dāng)中或者軟鏈接到/usr/bin下
  3. 指定要生成API文檔的swagger json文件進(jìn)行轉(zhuǎn)化须蜗,如下
    npx redoc-cli bundle -o index.html swagger.json
  4. 然后通過nginx建立一個(gè)server直接指向該index.html文檔即可硅确。配置示例:
server {
    listen 8081 default_server backlog=20480;
    listen [::]:8081 default_server;

    server_name localhost;

    access_log /home/ubuntu/logs/nginx/swagger-ui/swagger-ui.access.log main;
    error_log /home/ubuntu/logs/nginx/swagger-ui/swagger-ui.error.log;

    # 此處是存放index.html的目錄,作為根目錄
    set $doc_root_dir "/home/ubuntu/swagger/swagger-ui-master/dist";

    location / {
        root $doc_root_dir;
        index index.php index.html index.htm;
     }
    # 此處用于緩存相關(guān)的文件
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 15d;
    }
    # 用于Amazon配置的健康檢查
    location /health_check {
        return 200;
    }
}

Swagger與Django

我們可以在Django中直接生成API文檔明肮,但是需要兩個(gè)庫的支持菱农,一個(gè)是DRF(Django Rest Framework),另一個(gè)是drf_yasg

  1. 安裝庫
pip install djangorestframework
pip install drf-yasg
  1. 在項(xiàng)目url文件中(根url文件)添加如下代碼
from django.conf.urls import include, url
from django.contrib import admin
from django.shortcuts import redirect
from rest_framework import permissions
from rest_framework.decorators import api_view

from drf_yasg import openapi
from drf_yasg.views import get_schema_view

swagger_info = openapi.Info(
    title="Snippets API",
    default_version='v1',
    description="""This is a demo project for the [drf-yasg](https://github.com/axnsan12/drf-yasg) Django Rest Framework library.

The `swagger-ui` view can be found [here](/cached/swagger).
The `ReDoc` view can be found [here](/cached/redoc).
The swagger YAML document can be found [here](/cached/swagger.yaml).

You can log in using the pre-existing `admin` user with password `passwordadmin`.""",  # noqa
    terms_of_service="https://www.google.com/policies/terms/",
    contact=openapi.Contact(email="contact@snippets.local"),
    license=openapi.License(name="BSD License"),
)

SchemaView = get_schema_view(
    validators=['ssv', 'flex'],
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    url(r'^swagger(?P<format>.json|.yaml)$', SchemaView.without_ui(cache_timeout=0), name='schema-json'),
    url(r'^swagger/$', SchemaView.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    url(r'^redoc/$', SchemaView.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
    url(r'^redoc-old/$', SchemaView.with_ui('redoc-old', cache_timeout=0), name='schema-redoc-old'),

    url(r'^cached/swagger(?P<format>.json|.yaml)$', SchemaView.without_ui(cache_timeout=None), name='cschema-json'),
    url(r'^cached/swagger/$', SchemaView.with_ui('swagger', cache_timeout=None), name='cschema-swagger-ui'),
    url(r'^cached/redoc/$', SchemaView.with_ui('redoc', cache_timeout=None), name='cschema-redoc'),
    ...
    
]
  1. Settings文件的設(shè)置
    install apps需要有如下app
INSTALLED_APPS = [
    ...
    'django.contrib.staticfiles',
    'rest_framework',
    'drf_yasg'
]

middleware中需要添加如下中間件

MIDDLEWARE = [
    ...
    'drf_yasg.middleware.SwaggerExceptionMiddleware',
]

其它相關(guān)設(shè)置

SWAGGER_SETTINGS = {
    'DEFAULT_INFO': 'testproj.urls.swagger_info',
}
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'testproj', 'static'),
]

  1. 在Serializer中定義相關(guān)fields時(shí)加上help_text就可以了
class AssetSerializer(serializers.Serializer):
    supportWithdraw = BooleanField(
        read_only=True, help_text='if support withdraw')
    supportDeposit = BooleanField(
        read_only=True, help_text='if support deposit')
    fee = FloatField(read_only=True, help_text='withdraw fee rate')
    currency = CharField(max_length=10, read_only=True, help_text='asset name')
    info = AssetInfoSerializer()

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass
  1. 啟動(dòng)server后,可以通過訪問/swagger/ 或者/redoc/等路徑就可以看到對(duì)應(yīng)的文檔

Swagger與Flask

生成Flask代碼

我們可以通過swagger-py-codegen來生成對(duì)應(yīng)Flask的API代碼腳手架柿估,過程如下:

  1. 安裝swagger-py-codegen
pip install swagger-py-codegen
  1. .yml文件拷貝到你的目錄中循未,這里使用的是api.yml

  2. 進(jìn)入該目錄,執(zhí)行如下命令

swagger_py_codegen --swagger-doc api.yml example-app

這時(shí)就可以看到目錄中生成的Flask代碼官份,目錄結(jié)構(gòu)如下:

example-app
├── example_app
│   ├── __init__.py
│   └── v1
│       ├── __init__.py
│       ├── api
│       │   ├── __init__.py
│       │   ├── pets.py
│       │   └── pets_petId.py
│       ├── routes.py
│       ├── schemas.py
│       └── validators.py
└── requirements.txt

swagger_py_codegen有如下選項(xiàng):

Options:
  -s, --swagger-doc TEXT   Swagger doc file.  [required]
  -f, --force              Force overwrite.
  -p, --package TEXT       Package name / application name.
  -t, --template-dir TEXT  Path of your custom templates directory.
  --spec, --specification  Generate online specification json response.
  --ui                     Generate swagger ui.
  --validate               Validate swagger file.
  -tlp, --templates TEXT   gen flask/tornado/falcon/sanic templates, default
                           flask.
  --version                Show current version.
  --help                   Show this message and exit.

需要注意的是選項(xiàng)--spec--ui可以幫助我們生成在線的API文檔只厘,使用示例:

swagger_py_codegen --swagger-doc api.yml example-app --ui --spec

這時(shí),執(zhí)行example_app/example_app下的init.py可以運(yùn)行起Flask server舅巷,在瀏覽器中輸入U(xiǎn)RL"http://0.0.0.0:5000/static/swagger-ui/index.html#/default/get_users_uid"就可以看到生成的API文檔。

References

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末河咽,一起剝皮案震驚了整個(gè)濱河市钠右,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忘蟹,老刑警劉巖飒房,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搁凸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡狠毯,警方通過查閱死者的電腦和手機(jī)护糖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嚼松,“玉大人嫡良,你說我怎么就攤上這事∠仔铮” “怎么了寝受?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)罕偎。 經(jīng)常有香客問我很澄,道長(zhǎng),這世上最難降的妖魔是什么颜及? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任甩苛,我火速辦了婚禮,結(jié)果婚禮上俏站,老公的妹妹穿的比我還像新娘浪藻。我一直安慰自己,他們只是感情好乾翔,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布爱葵。 她就那樣靜靜地躺著,像睡著了一般反浓。 火紅的嫁衣襯著肌膚如雪萌丈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天雷则,我揣著相機(jī)與錄音辆雾,去河邊找鬼。 笑死月劈,一個(gè)胖子當(dāng)著我的面吹牛度迂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播猜揪,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼惭墓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了而姐?” 一聲冷哼從身側(cè)響起腊凶,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后钧萍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褐缠,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年风瘦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了队魏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡万搔,死狀恐怖胡桨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蟹略,我是刑警寧澤登失,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站挖炬,受9級(jí)特大地震影響揽浙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜意敛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一馅巷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧草姻,春花似錦钓猬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至综膀,卻和暖如春澳迫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剧劝。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工橄登, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讥此。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓拢锹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親萄喳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卒稳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容