進階 RESTful API 討論

複習一下!並加入比較深入進階的部分,利用鐵人賽這個機會讓我再去認真查詢學習 RESTful API 的相關設計!雖然不是強制一定要這麼設計API,但是可以讓程式碼的可讀性更好!我想這是各位大大會想努力的地方。

確認一個資源

如之前的範例資源就是動物資源,設計RESTful API要先有一個客戶端資源,可以做查詢動物的資訊、建立、編輯、刪除,分別用HTTP不同的動詞,以客戶端(介接我們API的人)的方向去思考,不需要跟資料表一模一樣。

HTTP 動詞

  • GET: 讀取資源
  • POST: 新增資源
  • PUT: 替換資源
  • DELETE: 刪除資源
  • PATCH: 更新資源部份內容

GET 的動作相較安全,它不會變動更改到伺服器的資訊,主要用來查詢資料。

POST、DELETE、PATCH、PUT 則會依照對應的動詞做需要的動作,寫入資料庫,或一些商業邏輯。

一定會是這種模式 動詞+資源

POST http://127.0.0.1/animal

PUT、PATCH 差別

PUT 通常做替換一個資源功能。

PATCH 修改資源的部分內容。

我自己是這麼定義的,假設資料表內已經有一筆資料內容如下

{
  "id" : 1,
  "name" : "小白" ,
  "type" : "小型犬" ,
  "birthday" : "2019/1/29"
}

PUT : 動物資料整個替換掉 PUT 方式請求網址 /animals/1  修改編號1的資料,回傳資料內容都是ID 1但裡面的內容整個不同。

PUT下面的內容,那麼ID 1的資料就會全部被修改成小黑的資訊,所以請求的時候必須填寫所有欄位不然資料會變成預設值。

{
  "name":"小黑" ,
  "type":"大型犬",
}

--結果--
{
  "id" : 1,
  "name" : "小黑" ,
  "type" : "大型犬" ,
  "birthday" : null
}

PATCH 一筆動物資料,我只想修改name 那就傳送含有欄位名稱的內容給API。

假設當時聽錯小白是大白那就只給需要修改的資料即可。

{
  "name":"大白"
}

--結果--
{
  "id" : 1,
  "name" : "大白" ,
  "type" : "小型犬" ,
  "birthday" : "2019/1/29"
}

API路徑 前贅詞

GET  http://127.0.0.1:3000/api/animal/1

再建立API的過程以及維護上,如果API程式改動可能會導致界接API的 client端會有錯誤,我目前是在網址加上前贅詞的方式,會建立類似這樣的開頭 

例如:網域名稱 https://vnewin.com (是我的部落格)

API 會這樣加上前贅詞 https://vnewin.com/api/ 或者 https://api.vnewin.com/ 當作API的路徑

版本號的部分我偏向把它寫在網址上,所以會變成 https://vnewin.com/api/v1/ 後面才開始接資源路徑。

版本號的另外一種寫法

可以把版本號寫在 Headers 裡面,下次我會試試看,但我應該會先把,大更新比如說 v1 寫在URI,小幅變動的版本號在寫在Headers。

URI 格式

建議已小寫為主兩個字之間用減號「-」隔開。

資源名詞

資源複數名詞

如果對於client端來說,animals 有很多可讀取的資源,建議加上複數,但我自己對於這方面還是覺得有點奇怪,像新建一筆動物資料,用  POST api/animals  我看起來是感覺怪怪的! 

不過大多API設計一般都使用複數名詞。

唯一資源

但因為後來在設計User這樣的資源,對於一般的會員,就只會有一筆資料,他只能查詢他自己資料,刻意設計一個 users/1 來查詢自己的內容,對於客戶端的使用者覺得很沒有必要,而且與我管理端在操作 User API 有衝突,所以可能知道為什麼大多數用複數的原因。

假設一般會員,讀取他自己基本資料時,還要想辦法知道他的User id 實在有點奇怪。

就再有一天研究 GitHub 的 API 時發現 GET /user/subscriptions ,表示附上的token 登入會員的資源,對於user端來說,他可以這樣輕鬆查到自己的資料。

關聯資料

資源的層級架構,可以適當反應在URI上,例如  /animals/1/event 表示這隻動物的相關事件!

或是動物打狂犬疫苗,這個簡單的動作,因為狂犬病疫苗,每年要打一次,每次施打都做紀錄!因此可以請求

POST /animal/1/vaccination

這個請求會去新增施打狂犬疫苗資料表的資料。

{
  "date" : "2019-10-01"
}

Resource | Utility API

目前我查詢到的認知最常分兩種,一種 資源型Resource 就是操作資源的CRUD,另一種 Utility 功能型檢查。

例如 檢查優惠券是否可以使用或是搜尋功能 API 

GET /api/search?q={keywords}

可能還有一些特殊的操作,我會使用POST動詞來處理這些特殊的操作。

例如我們的系統想要讓使用者方便確認動物是否打過狂犬疫苗,也可以讓系統人性化一點訂製一個確認施打疫苗的 API 我認為也是可行的,最主要需求有符合系統的規劃,業主的希望。

所以再次強調,RESTful API就是一個設計的規範,沒有硬性規定一定要怎麼做,依照經驗打造一個好維護的API比較重要。

HTTP Header

最常看到的就是 Accept 以及 Authorization 我們之前的範例都有用到在發送請求的時候。

  • Accept 設定可以接受的回應內容類型
  • Authorization 認證 Token 的資訊

以上這些都是定義URI 以及發送請求方面的建議,讓開發者有好的語意可以了解API的運行方式,可以多看多比較,找到一個最適合專案的運用方式。


Response 回傳建議

Response Body

回傳資料的格式有很多種,但現在 JSON 格式算主流,系統也普遍支援,JSON 比較簡潔與XML相比的話,所以越來越多人採用JSON作為資料的傳遞。採用JSON或XML或同時支援兩種格式,仍應視專案的實際需求而定。 可能客戶端的系統都很舊,都使用XML 那你就要想辦法支援!

Errors 定義

就像 Html 錯誤頁面向訪問者顯示有用的錯誤消息一樣,API應該以已知的錯誤提供有用的錯誤消息,像Google 的api 有些還有說明頁面得連結。

這邊要特別談到HTTP狀態。一定要返回對應的狀態碼,打致上可以分為三種,成功的狀態碼200系列、400系列使用者的問題、500系列伺服器出錯的問題。

一個好的API建議的可以規格化所有400系列的錯誤返回提示,在返回的錯誤JSON資料中,應該要替開發者提供一些東西。

  • 錯誤代碼,方便查詢,也方便我們在開發API的過程撰寫文件
  • 錯誤訊息
  • 錯誤原因的敘述
{
  "code" : 123456,
  "message" : "發生錯誤!",
  "description" : "有關錯誤的錯誤訊息"
}

PUT,PATCH、POST 請求的驗證錯誤附上欄位敘述,這邊我都是直接用 Laravel 內建的驗證表單功能,返回的錯誤格式!

HTTP狀態碼總覽

HTTP 定義了一堆可以從API返回的有意義的HTTP狀態碼。可以利用這些來幫助API客戶端判斷對應動作。

我整理以下比較常用的狀態碼!提供給各位參考

操作成功之狀態碼

  • 200 OK - 成功的GET,PUT,PATCH或DELETE請求以及不是用於創建的POST請求。
  • 201 Created - 對POST的回應,創建成功。應與指向新資源位置的Location標頭結合使用
  • 204 No Content - 成功請求不返回資料的回應(如DELETE請求)
  • 304 Not Modified - 在HTTP緩存標頭設定時使用,If-Modified-Since

客戶端使用者的操作錯誤狀態碼

  • 400 Bad Request - 請求格式錯誤,資料無法解析
  • 401 Unauthorized - 未提供或無效的身份驗證Token時
  • 403 Forbidden - 身份驗證成功但無權訪問資源
  • 404 Not Found - 請求不存在的資源時
  • 405 Method Not Allowed - 當請求的HTTP方法不允許經過身份驗證的用戶時
  • 410 Gone - 表示此端點的資源不再可用。有用作舊API版本的一攬子響應
  • 415 Unsupported Media Type - 如果作為請求的一部分提供了錯誤的內容類型
  • 422 Unprocessable Entity - 用於欄位資料驗證錯誤
  • 429 Too Many Requests - 一定時間內請求次數超過伺服器設定值被拒絕

伺服器錯誤的錯誤狀態碼

  • 500 Internal Server Error - 伺服器端程式有誤,需要工程師修復

其它建議

  • 雖然API應該是無狀態(stateless),但之前有批量刪除或是修改的需求,我是有使用先請求刪除資料給伺服器!回傳刪除編號,再請求刪除。
  • Query parameter的部份 /api/search?q={keywords} 粗體部分,只要風格保持一致即可,REST 並沒有特殊規範。
  • REST API 所呈現的資源就如我們之前所述 URI 上的名稱 animal,跟資料庫可以不一樣!不一定要相同。

結語

RESTful API是一種設計風格,這種風格使API設計具有整體一致性,今天整理了網路上多位大神的文章,吸收內化以後,並且結合自己以前開發的經驗,提供給大家參考。

易於維護、擴展,並且充份利用HTTP協定的特點。這篇文章列出一些我認為較重要的部份,希望能幫助不熟REST API的人,在最短時間對它有個初步了解。

參考資料

更多HTTP 狀態碼

https://tw.twincl.com/programming/*641y

https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

https://charder.readbook.tw/api-design/restful

更多HTTP協定

Victor
Victor

哈囉!

文章: 233

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *