Swagger 是我目前用過的最優秀的 Api Doc 協議沒有之一。它與其他 Api Doc 協議(如apidocjs)最大的差別在於,Swagger 不僅僅可以定義 Api 的 Route / Request Param 和 Response,還可以定義 Definitions Object / Security Definitions Object 以及 Reference Object。
以一個電商專案為例,系統裡有 商品(Product)和 訂單(Order)兩個 Model,其中 Order 有一個 product_id
欄位用於關聯對應的商品;有兩個介面,一個是獲取商品詳情 /product/{product}
,另一個是獲取訂單詳情 /order/{order}
,為了減少Api請求數量,在獲取訂單詳情時我們希望同時返回對應的商品資料。
如果我們用 apidocjs 來寫的話,會是類似下面的註釋
/**
* @api {get} /product/:product Request Product information
* @apiName GetProduct
* @apiParam {Number} product Products unique ID.
* @apiSuccess {String} name Name of the Product.
* @apiSuccess {Number} price Price of the Product.
* @apiSuccess ... Others fields
*/
/**
* @api {get} /order/:order Request Order information
* @apiName GetOrder
* @apiParam {Number} order Orders unique ID.
* @apiHeader {String} Authorization Access Token.
* @apiSuccess {String} flow_no FlowNo of the Order.
* @apiSuccess {String} price Price of the Order.
* @apiSuccess {Object} product Product of the Order
* @apiSuccess {String} product.name Name of the Product.
* @apiSuccess {Number} product.price Price of the Product.
* @apiSuccess ... Others fields
*/
可以看到 Product 的欄位在兩個介面的註釋裡各寫了一遍,這就很繁瑣;另外一個更嚴重的問題是,如果未來 Product 表的欄位發生了增減,我們需要去修改每一個會輸出 Product 的介面的註釋,更繁瑣而且容易遺漏。
所以我們需要有一個可以定義 Model 欄位的功能,這就是 Swagger 的 Definitions Object,我們事先將 Product 和 Order 定義成 Definitions Object:
Product:
type: object
properties:
id:
type: integer
name:
type: string
price:
type: integer
Order:
type: object
properties:
id:
type: integer
flow_no:
type: string
product:
$ref: '#/definitions/Product'
在定義 Order 的 product 欄位時,我們使用了 $ref
,也就是 Reference Object,這就是告訴 Swagger,Order 的product 欄位指向了 Product 的定義。
再來看看 Route / Request Param 和 Response 在Swagger 中怎麼寫:
path:
/product/{product}:
get:
summary: Request Product information
parameters:
name: product
in: path
required: true
type: number
response:
'200':
description: Success
schema:
$ref: '#/definitions/Product'
/order/{order}:
get:
summary: Request Order information
parameters:
name: order
in: path
required: true
type: number
response:
'200':
description: Success
schema:
$ref: '#/definitions/Order'
通過 $ref
完美解決了增減欄位需要修改多處的問題。
我在第一次使用 Swagger 的時候,雖然被其強大的定義功能所折服,卻又對寫 Swagger 文件極其的厭惡,因為官方提供的 Swagger Editor 速度不僅慢,還時不時出錯,明明寫對了文件格式非要告訴我有問題,只能重新整理頁面重新載入。
直到最近發現了一個專案 swagger-php,通過註釋的方式來生成 JSON 格式的 Swagger 文件,只需要通過 \Swagger\scan()
函式掃描一個目錄下所有 PHP 檔案的註釋 (可以建立一個完全只有註釋的 php 檔案來放一些與 request / response 並無直接關聯的定義,比如 Security Definitions Object)。
有了 JSON 格式的文件之後,配合 Swagger UI 就可以展示出非常美觀的 Api 文件了,可以看這個 Demo,還支援在文件頁面直接發起 Api 請求,大大的方便!