# RESTful API ###### tags: `api` `http` ## HTTP 動詞 - GET: 讀取資源 - POST: 新增資源 - PUT: 替換資源 - DELETE: 刪除資源 - PATCH: 更新資源部份內容 GET 的動作相較安全,它不會變動更改到伺服器的資訊,主要用來查詢資料。 POST、DELETE、PATCH、PUT 則會依照對應的動詞做需要的動作,寫入資料庫,或一些商業邏輯。 ## 一定會是這種模式 動詞+資源 ``` POST http://127.0.0.1/animal ``` ## PUT、PATCH 差別 PUT 通常做**替換**一個資源功能。 PATCH **修改**資源的**部分**內容。 ## API路徑 前贅詞 ``` GET http://127.0.0.1:3000/api/animal/1 ``` 再建立API的過程以及維護上,如果API程式改動可能會導致界接API的 client端會有錯誤,我目前是在網址加上前贅詞的方式,會建立類似這樣的開頭 例如:網域名稱 [https://vnewin.com](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 ``` 這個請求會去新增施打狂犬疫苗資料表的資料。 ```json { "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的過程撰寫文件 - 錯誤訊息 - 錯誤原因的敘述 ```json { "code" : 123456, "message" : "發生錯誤!", "description" : "有關錯誤的錯誤訊息" } ``` PUT,PATCH、POST 請求的驗證錯誤附上欄位敘述,這邊我都是直接用 Laravel 內建的驗證表單功能,返回的錯誤格式! ## HTTP狀態碼總覽 HTTP 定義了一堆可以從API返回的有意義的HTTP狀態碼。可以利用這些來幫助API客戶端判斷對應動作。 我整理以下比較常用的狀態碼!提供給各位參考 ### 操作成功之狀態碼 - `200 OK` - 成功的GET,PUT,PATCH或DELETE請求以及不是用於創建的POST請求。 - `201 Created` - 對POST的回應,創建成功,並可回傳新建資源物件的資料。 - `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://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status) 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協定](https://zh.wikipedia.org/zh-tw/超文本传输协议) jsend標準:https://github.com/omniti-labs/jsend 規劃RESTful API要注意什麼:https://noob.tw/restful-api/