現代網站越來越多採用前後端分離架構:透過前端 MVC 框架快速堆砌 SPA,再透過 API 取得變動資料。連結前後端的 API 重要性不言而喻。對前端開發者而言,認識後端 API 設計也是必要的一環。本章探討 API 設計。
HTTP Method#
畢竟是網站的前後端,其中間的通訊,終究還是要仰賴 HTTP 這個無狀態的協定;在 HTTP 規範中有定義了一系列的 Request Method(HTTP Method),其中較常用到的如下:
| 方法 | 用途 |
|---|---|
| GET | 取得資源 |
| HEAD | 與 GET 同為取得資源,但只取回 Header |
| POST | 提交資源 |
| PUT | 取代指定資源 |
| PATCH | 修改指定資源 |
| DELETE | 刪除指定資源 |
| OPTION | 詢問與指定資源的溝通方法 |
在規範中也提到,不同的 Method 指的是對同一件事情做不同的操作,並透過語意化的(semantic)Methods,讓不同的操作結果得以被預期。
GET、POST 相信絕大多數的開發者都不陌生,這是 HTML 的 <form action="..."> 唯二支援的 Methods;GET 是最頻繁使用的,無論是取得頁面、資料,一般而言都會使用 GET,POST 則常用在新增資源,但由於前述的 HTML <form action="..."> 不支援其他 Methods,在傳統網站中可能會用 POST 處理除了取得資料以外的所有事情。
PUT 和 PATCH 通常都用在更新資源,兩者的差異是 PUT 預期的行為會是取代整個資源,而 PATCH 則是更新部分資源;把兩者對應到生活化案例的話,例如在餐廳吃飯,整桌重新點菜是 PUT,另外加點則會是 PATCH。
DELETE 通常用在刪除資源;HEAD 與 GET 同樣為取回資源,但只取回 Header,通常會用在測試資源是否存在;OPTION 是詢問這個資源應該要怎麼取得,常在發送 CORS 的預檢(preflight)請求時使用。
當然,目前講的都是規範提到且較建議的一般用法,實際伺服器的 API 怎麼開依然是看實作者;但透過語意化的 Methods 設計 API,絕對可以讓 API 對開發者更加友善。
RESTful API#
前述的只是規範,而且只圍繞在 HTTP Methods 上;有沒有更完整的實作方法建議呢?
當然有囉,就是大家耳熟能詳的 RESTful API;由 Roy Fielding 在 IETF 開發 HTTP 標準的六年間持續專研、驗證,並在 2000 年於博士論文《Architectural Styles and the Design of Network-based Software Architectures》中所提出,是一種網路程式的設計風格;這邊的 REST(Representational State Transfer)是表現層狀態轉換的縮寫,簡單說就是透過動詞(HTTP Methods)、名詞(URI/URL,代表目標資源)、內容型態(回應的內容,HTML、XML、JSON(JavaScript Object Notation)、etc.),讓無狀態的網路通訊能藉由 REST 的語意化設計,攜帶所有的狀態資訊,降低對網路通訊的重複請求資源消耗。
例如,有個假想的影音網站:mytube.com,開出來的 API 有可能就會長這樣子:
[GET] http://mytube.com/v1/videos/ -> 取得 video 列表
[POST] http://mytube.com/v1/videos/ -> 新增 video
[GET] http://mytube.com/v1/videos/MgphHyGgeQU -> 取得指定 ID 的 video
[PUT] http://mytube.com/v1/videos/MgphHyGgeQU -> 修改指定 ID 的 video
[DELETE] http://mytube.com/v1/videos/MgphHyGgeQU -> 刪除指定 ID 的 video除了使用的方法之外,也要注意代表資源的 URL 的撰寫方式,不是 HTTP Methods 與實際動作相符合就是 RESTful API 囉!
同樣的,RESTful API 只是設計風格,甚至不是 HTTP 的規範,很有可能設計時基於 RESTful 的精神,但實際開發的結果全然不是 RESTful 的風格;但不可否認的是,透過 RESTful API 的設計風格,每個資源都會得到一個對應的位置(URL),並能透過 HTTP 語意化的方法,對指定的資源做相對應的互動,整體資源管理便能非常語意化且清晰,確實是一個優秀的 API 設計方式。
規範與實作#
當規範與實作的差異太大時,會發生什麼事情;而 HTTP 的 Methods 在規範中也有提到要如何正確使用,如果開發者沒有依照規範,確實是會造成影響的。
快取#
例如網頁快取,瀏覽器預設行為會對 GET、HEAD 這兩個方法做快取,如果像標題說的取資料不是透過 GET 而是 POST,瀏覽器及中間的代理伺服器都很可能不會實作快取機制,就必須由前後端開發者自行透過其他方式設置快取。
在規範中雖然有提到
POST在 Header 合適的情況下也可以快取,但由於實務上通常把POST用在新增,快取起來反而會造成不預期的結果,大部分瀏覽器也都沒有實作POST的快取機制。
SEO#
搜尋引擎例如 Google 的爬蟲在掃網站時,如果看到需要透過 POST 取得的資源,為了避免造成意外的行為或副作用(改到資料),通常不會嘗試爬找 POST 回應的結果。
GraphQL#
RESTful API 的設計風格優點不少,但有一些缺點也是難以避免。
例如在查找有依賴關係的巢狀資料時,很有可能必須要經過多次來回,才能找到想要的結果;而隨著專案架構逐漸擴張,同一頁面的資料也會越來越複雜,可能需要多個來源的資料才能堆砌出頁面,這時候 RESTful API 指名每個資源位置的特性,就會讓 RESTful API 顯得不太好用;也因為現在行動裝置非常普遍,一個後端伺服器可能需要服務電腦版網頁、手機 APP 等多裝置的需求,需要的資料可能不一樣,RESTful API 也就必須要開出多個功能類似的端點,整體的 API 便會量多而龐雜,相對難以管理。
有這樣的需求,就會有解決需求的人;GraphQL 就應運而生了,這是一個由 Facebook 提出的開源語言標準,透過 Schema 定義資料,再透過與 JSON 格式高度類似的查詢語句,取得查詢的結果,主要有幾個特色:
- 強型別
- 查詢句即文件
- 查詢句即回應的資料結構,不會有冗餘的內容
- 統一的對外入口
- 可拼接查詢,一併送出
這些特性,有效的解決了前述 RESTful API 在複雜架構下的問題,使得 GraphQL 充滿彈性、非常好用,社群也已經有可觀的生態系支援,例如 Apollo GraphQL 與三大框架深度整合,配上可拼接查詢的特性,便能讓 GraphQL 與現代框架 Components 的概念完美契合。
缺點大概就是必須把所有複雜的資料串接邏輯都寫在後端,對於寫習慣 RESTful API 的開發者來說,需要付出不少學習成本。
值得注意的是,GraphQL 送出的請求全部都會是
POST,快取的機制必須仰賴開發者或是套件實現;例如在 Apollo Client 中,開發者必須依照應用情境,調整fetchPolicy的設定,避免快取造成的意外結果。
結語#
標題是一位朋友面試某公司後端工程師時被問到的題目。從此出發,我們依序理解了 HTTP Methods 與主流的 RESTful API 設計風格,並簡短介紹 GraphQL。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10227433