簡(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安裝
- 下載Swagger-Editor铐料。直接下載zip文件地址并解壓
- 下載并且安裝node.js
npm install -g http-server
- 進(jìn)入swagger-editor文件夾渐裂。運(yùn)行
http-server
命令。 - 在瀏覽器中輸入
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文檔啥供,如下圖:
通過[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安裝
- 下載Swagger-UI。直接下載zip文件地址并解壓
- 下載并且安裝node.js
npm install -g http-server
- 進(jìn)入swagger-editor文件夾贷屎。運(yùn)行
http-server -p 8081
命令罢防。 - 在瀏覽器中輸入
http://127.0.0.1:8081
即可看到Swagger-UI展示的界面
配置
- 首先將Swagger-Editor生成的json文件拷貝到swagger-ui主目錄下的dist文件夾
- 修改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>
- 重新啟動(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頁面。步驟如下:
npm install -g redoc-cli
- 有時(shí)
redoc-cli
無法直接使用同眯, 需要安裝npx
.
npm install -g npx
注意: 有些系統(tǒng)(比如Ubuntu)绽昼,其安裝位置為/opt目錄下,我們需要將其添加到path當(dāng)中或者軟鏈接到/usr/bin下 - 指定要生成API文檔的swagger json文件進(jìn)行轉(zhuǎn)化须蜗,如下
npx redoc-cli bundle -o index.html swagger.json
- 然后通過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
庫
- 安裝庫
pip install djangorestframework
pip install drf-yasg
- 在項(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'),
...
]
- 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'),
]
- 在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
- 啟動(dòng)server后,可以通過訪問
/swagger/
或者/redoc/
等路徑就可以看到對(duì)應(yīng)的文檔
Swagger與Flask
生成Flask代碼
我們可以通過swagger-py-codegen
來生成對(duì)應(yīng)Flask的API代碼腳手架柿估,過程如下:
- 安裝
swagger-py-codegen
pip install swagger-py-codegen
將
.yml
文件拷貝到你的目錄中循未,這里使用的是api.yml進(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文檔。