關於 RESTful API
在以前幾篇骨灰級的文章中曾經有介紹過 REST,接觸過 Web 開發的大大們多少都聽過、看過或夢到過 REST API,算是常聽到的技術名詞。那麼 RESTful 到底是什麼?其實 RESTful 並不是什麼獨特的技術規範,RESTful 是一種「軟體架構風格」,這樣的解釋聽起來是不是很玄!?實務上要如何設計 REST API 呢?開始之前,我們先回顧一下重要的 RESTful-Triangle (REST 金三角) 概念:
右邊這個三角形描述了以下三個重要的概念:
- Nouns 名詞:用來定義你的網址 URL,記住,每一個網路上的資源應該僅有一個唯一的識別位置,就像你的房子有獨一無二的「住址」一樣。
- Verbs 動詞:描述了對 Nouns 名詞 (資源 URL) 的操作動作,在 HTTP 1.1 的實作當然就是 HTTP Method。比如用 GET 取得文章內容、用 DELETE 刪除文章等等行為。
- Content Types 資源呈現方式:比如取得某一個 URL 文章的 HTML 格式、或者 XML 格式,同樣的 URL 資源可以有不同型態的表現方式。
建議在設計 API 規格時,同時思考上述的設計原則,好讓 API 設計更接近 REST 精神。
這幾年參與並重構了一些不同的系統,也認識一些很棒的開發團隊,大部分對於 REST 的接受程度都相當樂觀。但 RESR 應用在實務的 API 設計上,常遭遇不同複雜的業務情境,不一定能夠將 API 設計的很 RESTful,在看過不少 REST API 規格文件之後,歸納了幾點常犯的錯誤,順便警惕自己未來不要踩到雷了。
用了 GET, POST, PUT, DELETE 不等於 RESTful API?
這類的錯誤蠻常遇見的,常常只是把刪除動作透過 DELETE 進行呼叫,而缺少對 URL 的設計與資源定義,URL 中也常常出現動詞 (描述行為),舉個錯誤的例子:
上傳文章 POST /api/article/upload
刪除文章 DELETE /api/article/remove
看出來問題在哪了嗎?就是 URL 的設計問題,比較正確的 REST API 會設計一個唯一的 URL 來表示資源,URL 中文叫做「統一資源定位符」,顧名思義用來識別你的資源在 WWW 唯一的位置。將 ID (或 GUID) 設計在 URL 中是比較建議的做法,上述的錯誤示範可以修正如下:
上傳文章 POST /api/article 文章建立完成後回傳 Location Header 告知新資源的 URL
刪除文章 DELETE /api/article/{ARTICLE_ID}
另一個常遇到的不良設計就是把 ID 放在 Query String 中,像是以下錯誤的例子:
刪除文章 DELETE /api/post?pid=7533967
請避免將 ID 設計在 Query String 中,Query String 雖然是網址的一部分,Query String 表示對這個實體進行 Query 時加入額外的條件過濾或參數,過度依賴 Query String 傳遞參數不是一個明智的行為。此外,HTTP 其實有定義了很多 HTTP Method 可以使用,如果你真的找不到適合的 HTTP Method,也可以使用 POST Method 來描述一個會改變 Server 資源狀態的 API 規格,盡可能不要透過 GET Method (Safe Methods) 執行一些像是新增、刪除、修改等等操作。
多利用 HTTP 既有的設計來實現 API 功能
其實 HTTP 已經定義了很多好用的規格,我們可以遵循這些設計,舉幾個例子:
- 透過 HTTP Status Code 回傳 API 執行結果
- 利用 HTTP Accept Header 告知 Server 指定回傳的資料格式 Content-type,JSON 可以送出 application/json、XML 可以送出 application/xml 等等
- 透過 POST 新增資料到 Server,執行成功後回傳 201 Status Code 並且透過 Location Header 告知新資源的 URL
由於 HTTP 1.1 (RFC 2616) 本身就是 REST 架構的實踐,能夠盡可能多了解 HTTP 與正確地使用 HTTP,理所當然就是 RESTful 的最佳實踐囉。
採用 RESTful 風格設計的 API 還有哪些好處?
好的 URL 設計幫助除錯工作,我們想想,如果 URL 與 Method 可以描述資源對象與操作方法,搭配 Status Code 回傳操作結果,那麼 HTTP Server Access Log 在除錯上就會變得更有價值,可以直接由 Access Log 發現 API 的呼叫流程並推斷 Server 狀態的轉變,對於除錯是很有幫助的。此外,REST 設計將每一個實體定義獨立唯一的 URL 位置,物件資源相互的依賴性降低,API 解耦特性更好,容易彈性組合應付多數業務邏輯,也是優點之一。
採用 RESTful 有什麼壞處?
REST 也不是萬能的,除了優點也是有許多在實務上應用的缺點。比如查詢時常被詬病資源相依結構鬆散問題,有時候取資料時都要呼叫好多次 API 才可以組合成完整的物件。舉個例子,想要取得文章與作者資訊,就必須先 GET /文章/{ID},然後再透過取回的文章物件中的 Author 欄位再一次呼叫 GET /使用者/{NAME} 取得作者資訊,挺麻煩的。像是最近興起的 GraphQL (由 Facebook 發佈) 就可以解決 REST 取相依結構資料的問題,整體來說 ORM 的實踐概念更好了,也剛好呼應近幾年熱門的 NoSQL 設計,GraphSL 在查詢方面我覺得是比 REST 優秀,但設計上免不了失去了一些 REST/HTTP 既有的概念,就看未來的發展如何了....... 今天先到這裡,下次見!