導入 Swagger 於開發團隊,建立 API 文件化的第一步

J米的學習日記
Parenting 數位研發
14 min readOct 21, 2022

這是我的一小步,卻是人類的一大步,這句話出自於 Neil Armstrong,當然結果沒這麼偉大,但文件化的確是開發者邁向 Happy Coding 的一大步。

近期,自己在研究 Api 文件化,剛好我們電商這個團隊,還沒有人導入,
成了我第一次自動請纓去研究一套工具的契機,經研究後,發現導入並不困難,來看看我怎麼做的吧!

文件化的必要性

好端端的,為什麼需要導入一個陌生的工具去建立文件? 其他團隊成員或許會有這個疑問,不知道你是否在公司專案 codebase 中看過在 function 上面有這些註解?

UserController

以上面的程式碼為例,這些註解的功用,都是下一個工程師(你或我)在下一次看到這段程式碼時,快速理解這段 code 的商業邏輯,以及它要處理什麼事情的加速器。

那問題來囉!
1.
PM 怎麼知道這支 Api 的功能是什麼呢?

2. 前端工程師剛接手專案時,要怎麼快速上手知道 Api 要丟哪些參數,才能得到他(她)想要的結果 ?

3. 承上題,外包的工程師也想知道上述的事情,要怎麼辦呢 ?

仔細想想,他們沒有權限看到上面這段程式碼,不是嗎?
他們怎麼知道這個 Api Route 連到哪個 Controller? 需要帶哪些參數?

回到問題本身,身為開發利害關係人到底要怎麼快速且無痛的使用這個 Api 完成我想做的事情?

那你一定看過這樣的文件,記載著 Api 的介紹,使用此 Api 要接收的資料、回傳的資料、回傳資料的欄位名稱意義等等,如下圖。

Api 功能:拿取使用者歸戶折價券
Spec: https://spec.com.tw
目的:...
Http 請求方式:GET
測試機 Url: https://test.com.tw
正式機 Url: https://production.com.tw
query params:
1. type: all/used/on_air/future/expired
2. order_column: id/discount/expires_at
3. order_by: asc
example: https://test.com.tw/api/v1/users/vouchers?type=on_air&order_column=expires_at&order_by=asc
response:
1. 200 success
{
"code": 200,
"message": '',
"data": [
{
"id": 1,
"name": "持續到雙 11 的折價券",
"mode": 1,
"value": 50,
"expires_at": "2022-11-12 00:00:00"
"gate": 500,
"code": "double11"
}
]
}
2. 422 validate error
{
"code": 422,
"message": {
"order_column": [
"order_column 須為 string"
],
"type": [
"type 須為 string"
]
},
"data": []
}
3. 401 Unauthorized
{
"code": 401,
"message": "Unauthorized'
"data" => null
}

上面相似文件,格式或許不同,但身為開發者或是專案相關人員一定看過,一個人一個寫法,一百種人就一百種寫法,當沒有一個統一工具去規範,加上文件散落到各地,一下子 word,一下子內部文件、一下子 markdown 工具,就真的是一份文件,各自表述了!

話說回來,哪一款文件管理工具團隊用起來比較容易上手、功能比較多,這不是一個選青菜還是蘿蔔的問題,這是需要團隊坐下來一起討論才有的共識,比較各種工具的優缺點,討論決議好,進行導入文件管理工具,工程師每完成一個需求,就必須把文件補上,避免文件與程式不同步的狀況發生。 有了明確的動機後,我挑了兩個 Api 文件化的工具,Swagger & ApiDocs,讓我們一起來看它們的優缺點吧!

Swagger 套件優缺點

先看個畫面吧!給個感覺,才不會沒有憑空想像。 以下為 Swagger 提供的 Live demo

Swagger demo 圖片來源 petstore swagger UI

優點:

  1. 介面好看
  2. 文件會產生輕量 json 靜態檔,每次刷頁面,去讀取 json 去 render 畫面
  3. 互動性操作高(有類似 Postman 功能)
  4. 網路資源多(可以快速找到寫法),超級重要,不會的時候可以上社群問
  5. 其他研發部門有使用過的經驗(有人問總比沒人問好)
  6. 相較於 ApiDocs,較多團隊使用 Swagger 作為 Open Api

缺點:

  1. 寫法較難上手
  2. 寫法在頁面上看起來很冗長

這邊補充一下 Open Api 是什麼? Open Api Specification 又是什麼? 這裡有一個 Open Api 網站畫面,讓讀者更容易想像。

Open Api 是對大眾公開的 Api 介面,可以給每個開發者使用與操作,因此可以藉由這些 Open Api 取得資料。
每個工程師都有自己寫文件的方法,因此 Open Api Specification 就是 Open Api 的規範,又可簡稱為 OAS,有一個明確且公認的規範去撰寫這些文件。
舉例來說:想要串 Twitch 直播的 Api,你必須先看 Twitch 提供的 Open Api。

ApiDocs 套件優缺點

電腦本機端 build apiDocs 畫面
ApiDocs demo 圖片來源 apidocsjs

優點:

  1. 寫法簡單上手快
  2. 寫法精簡,跟註解 PHP Docblocker 寫法很像,不會太難懂

缺點:

  1. 產生大量靜態檔 markdown 與一些 css, html
  2. 研究後發現,每次有修改都必須執行一次,重新產生靜態檔
  3. 網路資源少
  4. 功能沒有互動性,沒找到開啟選項
  5. 研究後還找不到 snippets

上吧,Swagger,就決定是你了!

分析了不同 API 文件化工具的優缺點,讓團隊有共識,並進行良好的溝通與討論! 票數一面倒的選擇 L5-Swagger 進行導入原因歸納有以下三點:

  1. 使用者畫面好看
  2. 其他開發團隊導入過,如果不清楚有人可以詢問
  3. 不用產生靜態檔,可以自己重新 re-render,不用一直重複下指令
    由此可見,工具方便性、使用者畫面、有前人可以問

Swagger 導入實戰演練 — 參數設定

筆者團隊使用 darkaonline/l5-swagger: "6.*"

  1. 用 composer 進行安裝吧!
composer require "darkaonline/l5-swagger:6.*"

2. setting of swagger provider

php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"

3. 在 Laravel config/app.php 設定 ServiceProvider

4. 設定 app/Provider/AppServiceProvider

public function register()
{
$this->app->register(\L5Swagger\L5SwaggerServiceProvider::class);
}

5. 產生 API 文件,下個指令,魔法就出現囉!

php artisan l5-swagger:generate

6. 備註:如有遇到問題,可能是你 app/Http/Controllers/Controller.php 沒有加上 OA 規範,因為大家都會繼承這個 Controller。詳細可以參考這篇,底下是我的設定。

如果上述進行的順順利利就會看到畫面囉!!! 讓我們一起倒數

Swagger 成功 Build 成功畫面

好的開始是成功的一半,挑戰現在才開始

當然,你 Build 成功的畫面一定空空如也,但別氣餒,你需要的是懂更多 Swagger doc 的編寫知識,讓我們一起學而時習之,不亦樂乎吧!

友善提醒:以下為示範案例,非真實情境哦

  1. swagger array 要用 {} 替代 []
  2. tags 代表 Api 分類
  3. path 你的 Api 路徑,也可以於 url 代入參數
  4. summary 描述 Api
  5. @OA\Parameter 說明 url 的 path or query 如何定義
  6. @OA\Property 說明此 Api 屬性屬性,可以用於 Schema, RequestBody, Response 等說明欄位屬性與型態
  7. @OA\Response 描述回傳 response 定義、格式、型態與範例
  8. @OA\MediaType 用來描述內容,可用於 response 內容描述
  9. @OA\Examples 說明不同的情境示範參數
  10. @OA\Schema 定義欄位格式,也可以將規範寫在 model 內,然後引用在 Controller 內,例如:@OA\Schema(ref="#/components/schemas/Promotion") 以下面為 Prmotion 促銷為例,如 requestBody & Response 引用此 Schema 可以讓使用者馬上了解其格式。
  • required 如 POST/Patch 必填
  • example 範例參數
  • readOnly 是否開放更新
  • format 格式

11. @OA\Response 用來描述回傳內容,可以自定義或利用剛剛定義 Schema 回傳及,例如:@OA\JsonContent(ref="#/components/schema/Promotion"),就是你剛才定義的 Model Schema。

  • 寫法一:如剛好回傳格式與 Schema 形式相同
*   @OA\Response(*     response=200,*     description="Successful operation",*     @OA\JsonContent(ref="#/components/schemas/Promotion")*   )
  • 寫法二:自定義 Response
*   @OA\Response(response=200, description="成功",*      content={*          @OA\MediaType(*              mediaType="application/json",*                  example=*                    {*                      "code": 200,*                      "message": "",*                      "data": {*                          "result": true*                      }*                   }*          )*       }*   ),

12. @OA\RequestBody 定義 payload 要傳的參數與格式,也提供兩種寫法,給讀者參考,取決於 API 情境與參數形式。

  • 寫法一:用於 Post / Patch 有明確定義的 Schema
*   @OA\RequestBody(*      @OA\MediaType(*          mediaType="multipart/form-data",*          @OA\Schema(ref="#/components/schemas/Promotion")*     )*   ),
  • 寫法二:自定義,情境為綁定某促銷只適用於某些產品
*   @OA\RequestBody(*      @OA\JsonContent(*        type="object",*        @OA\Property(property="promotion_id", type="integer", default="83"),*        @OA\Property(property="product_ids", type="arrays", default={1, 2, 3}),*        examples = {*          @OA\Examples(example="範例", summary="此促銷只能用於1,2,3商品內", value={"id": "83", "product_ids": {1, 2, 3}}),*        }*     )*   ),

13. 有些 Api 會設定特定 token 才可有權限取得其資料,其設定可谷歌搜尋一下,也可參照這篇

  • l5-swagger.php 須設定 bear_token
'bearer_token' => [ // Unique name of security'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2".'description' => 'Enter token in format (Bearer <token>)','name' => 'Authorization', // The name of the header or query parameter to be used.'in' => 'header', // The location of the API key. Valid values are "query" or "header".],
  • 在 Controller 前加上 SecurityScheme 讓 Swagger 知道這個 API 需要有 token 才能取的資料
/*** @OAS\SecurityScheme(*      securityScheme="bearer_token",*      type="http",*      scheme="bearer"* )*/class PromotionController extends Controller{
}
  • 每個 Api docs 設定 security security={{"bearer_token":{}}},

Swagger 示範寫法

Get 寫法

以下是 Get 寫法,搭配 summary 介紹,可以知道這隻 API 做的事情為前端要拿到後端促銷的顯示。

Create 寫法

以下是 Create 寫法,搭配 summary 介紹,可以知道這隻 API 為後台人員設定新增促銷時,將資料 POST 至後端。

Update(Patch) 寫法

更新促銷,可以知道這隻 API 為後台人員設定更新促銷時,將資料 POST 至後端。

其他案例 — 計算購物車

當我要 POST 的資料並非為標準格式時,可以在 RequestBody 自定義,Response 也可以自定義格式。

學習心得

Swagger 作為 API 文件,可以在團隊內作為 PM 或是其他非此專案開發者,快速理解與操作 API 的入門文件,對外面合作廠商或外包團隊,可以使用 Open API 標準格式,讓他們在測試環境中,能更快速了解如何串接與使用它, 不管選擇哪一個 API docs 工具,主要的目的都在於,可以讓團隊更有效降低溝通成本,提升開發效率!

然而,網路上 Swagger 撰寫語法比較雜亂,需要東拼西湊,才有辦法實現某種特定功能,特別是 Laravel 內的寫法,資源較少,筆者在撰寫過程中,也是常常踩雷,去嘗試不同的語法,去實現自己想要的結果。

中文資源的 Swagger 教學比較少,筆者想透過自己撰寫的學習經驗,去補充網路上這塊資源的不足,算得上是貢獻自己的微薄之力!
希望看到這篇的讀者,對你有所幫助,藉此整理出自己 Swagger 語法與紀錄自己的學習心得,也算是一大成就!

很開心這次導入 Swagger 成功,增加了溝通效率與導入工具上的經驗,真是可喜可賀!

參考資料

--

--