使用swagger 生成 Flask RESTful API

goodspeed發表於2017-07-11

什麼是 RESTful

什麼是REST

REST(英文:Representational State Transfer,又稱具象狀態傳輸)是Roy Thomas Fielding博士於2000年在他的博士論文 中提出來的一種全球資訊網軟體架構風格,目的是便於不同軟體/程式在網路(例如網際網路)中互相傳遞資訊。

REST 的核心是可編輯的資源及其集合,用符合 Atom 文件標準的 Feed 和 Entry 表示。每個資源或者集合有一個惟一的 URI。系統以資源為中心,構建並提供一系列的 Web 服務。

在 REST 中,開發人員顯式地使用 HTTP 方法,對系統資源進行建立、讀取、更新和刪除的操作:

  • 使用 POST 方法在伺服器上建立資源
  • 使用 GET 方法從伺服器檢索某個資源或者資源集合
  • 使用 PUT 方法對伺服器的現有資源進行更新
  • 使用 DELETE 方法刪除伺服器的某個資源

如果一個架構符合REST原則,就可以稱它為RESTful架構

RESTful API 設計定義

以下是幾個RESTful API的幾個概念。

  • 資源(Resource):系統上的所有事物都被抽象為資源(一篇文章,一張照片,一段語音)
  • 集合(Collection):一組資源的合輯稱為集合(幾篇文章,幾張照片)
  • 路徑(Endpoint):路徑又稱”終點“,表示API的具體網址(每個網址代表一種資源)

那麼一個設計良好的RESTful API應該遵循哪些原則呢?

協議

API與使用者的通訊協議總是使用HTTPs協議。

域名

應該儘量將API部署在專用域名,例如:

https://apis.gusibi.com複製程式碼
API地址和版本

在url中指定API版本。比如:

https://apis.gusibi.com/v1複製程式碼
以資源為中心設計URL

資源是RESTful API的核心元素,所有的操作都是針對特定資源進化的。而資源就是URL表示的,所以簡潔、清晰、結構化的URL設計是至關重要的。
在RESTful 架構中,每個網址代表一種資源(resource),所以網址中不能有動詞,只能有名詞,而且所用的名詞往往與資料庫的表格名對應。我們來看一下 Github 的例子:

/users/:username/repos
/users/:org/repos
/repos/:owner/:repo
/repos/:owner/:repo/tags
/repos/:owner/:repo/branches/:branch複製程式碼
使用正確的Method

對於資源的具體操作型別,使用HTTP method 表示。
以下是常用的HTTP方法。

  • GET:從伺服器取出資源
  • POST:在伺服器新建一個資源
  • PUT:在伺服器更新資源(客戶端提供改變後的完整資源
  • PATCH:在伺服器更新資源(客戶端只提供改變了屬性)
  • DELETE:從伺服器刪除資源

還是使用 github 的例子:

GET /repos/:owner/:repo/issues
GET /repos/:owner/:repo/issues/:number
POST /repos/:owner/:repo/issues
PATCH /repos/:owner/:repo/issues/:number
DELETE /repos/:owner/:repo複製程式碼
正確的過濾資訊(filtering)

如果記錄數量很多,伺服器不能都將他們返回給使用者。API應該提供引數,過濾返回結果。

下邊是一些是、常見的引數。

  • ?limit=10: 指定返回記錄的數量
  • ?offset=10:指定返回記錄的開始位置
  • ?page=2&per_page=100::指定第幾頁,以及每頁的記錄數。
  • ?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。
  • ?animal_type_id=1:指定篩選條件
選擇合適的狀態碼

HTTP 應答中,需要帶一個很重要的欄位:status code。它說明了請求的大致情況,是否正常完成、需要進一步處理、出現了什麼錯誤,對於客戶端非常重要。狀態碼都是三位的整數,大概分成了幾個區間:

2XX:請求正常處理並返回
3XX:重定向,請求的資源位置發生變化
4XX:客戶端傳送的請求有錯誤
5XX:伺服器端錯誤

常見的狀態碼有以下幾種:

200 OK - [GET]:伺服器成功返回使用者請求的資料,該操作是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:使用者新建或修改資料成功。
204 NO CONTENT - [DELETE]:使用者刪除資料成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:使用者發出的請求有錯誤,伺服器沒有進行新建或修改資料的操作,該操作是冪等的。
401 Unauthorized - []:表示使用者沒有許可權(令牌、使用者名稱、密碼錯誤)。
403 Forbidden - [
] 表示使用者得到授權(與401錯誤相對),但是訪問是被禁止的。
404 NOT FOUND - []:使用者發出的請求針對的是不存在的記錄,伺服器沒有進行操作,該操作是冪等的。
406 Not Acceptable - [GET]:使用者請求的格式不可得(比如使用者請求JSON格式,但是隻有XML格式)。
410 Gone -[GET]:使用者請求的資源被永久刪除,且不會再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 當建立一個物件時,發生一個驗證錯誤。
500 INTERNAL SERVER ERROR - [
]:伺服器發生錯誤,使用者將無法判斷髮出的請求是否成功。

返回結果

針對不同操作,伺服器向使用者返回的結果應該符合以下規範。

GET /collection:返回資源物件的列表(陣列)
GET /collection/resource:返回單個資源物件
POST /collection:返回新生成的資源物件
PUT /collection/resource:返回完整的資源物件
PATCH /collection/resource:返回完整的資源物件
DELETE /collection/resource:返回一個空文件

錯誤處理(Error handling)

如果出錯的話,在response body 中通過 message 給出明確的資訊。如果狀態碼是4xx,就應該向使用者返回出錯資訊。

良好的文件

文件應該是規範的API的重要的組成部分,沒有文件的API是難以給他人使用的,也是不利於維護的。

其它
  • 使用 OAuth2.0 鑑權
  • 儘量使用JSON作為返回的資料格式
  • 限流

對應上述規則,我們並不能保證其它的API提供者也會遵守,特別是文件,有很大一部分API提供者給出的文件是pdf或者word文件,這是因為在API的迭代開發過程中,文件更新會比較麻煩。

swagger幫API使用者和開發者糾正了這個問題。

什麼是swagger

Swagger是一個簡單但功能強大的API表達工具。改框架為建立JSON或YAML格式的RESTful API 文件提供了OpenAPI規範。swagger文件可由各種程式語言處理,可以在軟體開發週期中嵌入原始碼控制系統中,以便進行版本管理。使用Swagger生成API,我們可以得到互動式文件,自動生成程式碼的SDK以及API的發現特性等。

如何編寫API文件

我們可以選擇使用JSON或者YAML來編寫API文件。文件示例如下:

json 格式文件:

{
    "swagger": "2.0",
    "info": {
        "version": "1.0.0",
        "title": "Simple API",
        "description": "A simple API to learn how to write OpenAPI Specification"
    },
    "schemes": [
        "https"
    ],
    "host": "simple.api",
    "basePath": "/openapi101",
    "paths": {
        "/persons": {
            "get": {
                "summary": "Gets some persons",
                "description": "Returns a list containing all persons.",
                "responses": {
                    "200": {
                        "description": "A list of Person",
                        "schema": {
                            "type": "array",
                            "items": {
                                "properties": {
                                    "firstName": {
                                        "type": "string"
                                    },
                                    "lastName": {
                                        "type": "string"
                                    },
                                    "username": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}複製程式碼

yaml 格式文件:

swagger: "2.0"

info:
  version: 1.0.0
  title: Simple API
  description: A simple API to learn how to write OpenAPI Specification

schemes:
  - https
host: simple.api
basePath: /openapi101

paths:
  /persons:
    get:
      summary: Gets some persons
      description: Returns a list containing all persons.
      responses:
        200:
          description: A list of Person
          schema:
            type: array
            items:
              required:
                - username
              properties:
                firstName:
                  type: string
                lastName:
                  type: string
                username:
                  type: string複製程式碼

可以發現,yaml格式的文件比json格式的更清晰,可讀性更高,推薦使用yaml格式書寫文件。

swagger 官網提供了 swagger editor: http://editor.swagger.io/#/,你可以在這個編輯器中建立或匯入文件,並在互動式環境中瀏覽它。

以下是您匯入 leads.yaml 定義後的 Swagger Editor UI 外觀:

Swagger Editor UI 外觀
Swagger Editor UI 外觀

右側的顯示窗格顯示了格式化的文件,反映了在左側窗格中的程式碼編輯器中執行的更改。程式碼編輯器會指出了所有格式錯誤。你可以展開和摺疊每個窗格。

API文件的基本結構

我用一個例子來介紹下swagger文件的基本結構,這裡我用yaml格式來編寫文件:

swagger: "2.0"
info:
  title: Sample API
  description: API description in Markdown.
  version: 1.0.0

host: api.example.com
basePath: /v1
schemes:
  - https

paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in Markdown.
      produces:
        - application/json
      responses:
        200:
          description: OK複製程式碼

上述文件包括後設資料(Metadata)、Base URL、API路徑(paths)三部分:

Metadata

這部分資訊包括swagger 使用的版本:

swagger: "2.0"複製程式碼

API相關的描述資訊(比如API介紹、版本等):

info:
  title: Sample API
  description: API description in Markdown.
  version: 1.0.0複製程式碼

Base URL

作為web API,一個很重要的資訊就是用來給使用者使用的 根URL,可用協議(http/https)、host地址:

host: api.example.com
basePath: /v1
schemes:
  - https複製程式碼

所有的API都是base URL 的相對路徑 例如 /users 的API地址是 https://api.example.com/v1/users

路徑(Paths)

paths 部分定義API的路徑(endpoint)、支援的HTTP 請求方法

paths:  # 宣告路徑
  /users:  # 定義API路徑
    get:   # 定義請求方式
      summary: Returns a list of users.  # 簡介
      description: Optional extended description in Markdown.  # 描述
      produces:
        - application/json    # 定義 服務端response MIME types 
      responses:
        200:    # response 狀態碼
          description: OK複製程式碼

當然這只是個最簡單的例子,swagger可定義的內容要比我提到的多的多。
具體詳細資訊可以看下 swagger 文件:https://swagger.io/docs/specification/what-is-swagger/

當然,寫完文件並不代表我們的程式碼就可以直接使用這份文件以及文件中的約束,swagger 還提供了 swagger-codegen:https://github.com/swagger-api/swagger-codegen

swagger_codegen

swagger-codegen 是一個開源的程式碼生成工具,它包含一個模板驅動引擎,可以直接從我們定義的 swagger 文件中生成視覺化的文件檢視介面和API客戶端。

這是一個開源的專案,地址是swagger-codegens: https://github.com/swagger-api/swagger-codegen。可以自己安裝使用一下。

因為我最常用的語言是Python,所以給大家介紹一個第三方的 python 的程式碼生成器swagger-py-codegen:https://github.com/guokr/swagger-py-codegen

swagger_py_codegen

swagger-py-codegen的亮點是它是一個Python web framework 程式碼生成器,可以根據swagger 文件自動生成相應web framework 的程式碼,現在支援 Flask, Tornado,falcon,最新版將支援sanic。

安裝

可以使用 pip 安裝:

pip install swagger-py-codegen複製程式碼

使用

安裝後使用命令如下:

swagger_py_codegen --swagger-doc api.yml example-app複製程式碼

可選引數有:

-s, --swagger, --swagger-doc    Swagger doc file.  [required]
-f, --force                     Force overwrite.
-p, --package                   Package name / application name.
-t, --template-dir              Path of your custom templates directory.
--spec, --specification         Generate online specification json response.
--ui                            Generate swagger ui.
-j, --jobs INTEGER              Parallel jobs for processing.
-tlp, --templates               gen flask/tornado/falcon templates, default flask.
--version                       Show current version.
--help                          Show this message and exit.複製程式碼

如果不指定 -tlp 引數,預設使用 flask 作為模板。
如果指定 --ui --spec 引數則會在 由-p 引數指定的目錄下生成swagger UI 目錄 static。

舉個例子

我們這裡使用 swagger-py-codegen 提供的測試文件 執行:

swagger_py_codegen --swagger-doc api.yml example-app --ui --spec複製程式碼

生成的程式碼目錄結構如下

$tree
.
|__ api.yml

$ swagger_py_codegen -s api.yml example-app -p demo
$ tree (flask-demo)
.
|__ api.yml
|__ example-app
   |__ demo
   |  |__ __init__.py
   |  |__ v1
   |     |__ api
   |     |  |__ __init__.py
   |     |  |__ oauth_auth_approach_approach.py
   |     |  |__ oauth_auth_approach.py
   |     |  |__ users_token.py
   |     |  |__ users_current.py
   |     |  |__ users.py
   |     |__ __init__.py
   |     |__ routes.py
   |     |__ schemas.py
   |     |__ validators.py
   |__ requirements.txt複製程式碼

可以看到,這時一個簡單的app框架已經生成了,其中 routes.py 是自動生成的路由,validators.py 是response和request的校驗程式碼,schemas.py 是由文件生成的校驗規則,api 目錄下的各個檔案是你定義的endpoint。

這時執行demo 目錄下的 __init__.py 檔案:

python __init__.py複製程式碼

會發現 server 已經啟動:

server 啟動示例
server 啟動示例

如果生成命令帶上 --ui --spec,生成程式碼的同時也會生成swagger UI:

swagger_py_codegen --swagger-doc api.yml example-app --ui --spec複製程式碼

啟動server後在瀏覽器輸入地址 http://0.0.0.0:8000/static/swagger-ui/index.html#!/default/get_users_uid

可以看到直接使用的 swagger UI。

swagger ui 截圖
swagger ui 截圖

swagger-py-codegen 認證預設使用 OAuth2 認證方式,認證部分程式碼需要自己實現。

現在程式碼結構已經生成,可以安心的寫邏輯程式碼了。

總結

這一篇主要介紹了RESTful API以及如何使用swagger編寫規範的RESTful API。
最後介紹瞭如何使用 swagger-py-codegen 生成 web framework 的結構程式碼。
參考連結中的文章都非常值得一看,建議都看一下。

參考連結


最後,感謝女朋友支援。

歡迎關注(April_Louisa) 請我喝芬達
歡迎關注
歡迎關注
請我喝芬達
請我喝芬達

相關文章