現代網站越來越多採用前後端分離架構:透過前端 MVC 框架快速堆砌 SPA,再透過 API 取得變動資料。連結前後端的 API 重要性不言而喻。對前端開發者而言,認識後端 API 設計也是必要的一環。本章探討 API 設計。

HTTP Method#

畢竟是網站的前後端,其中間的通訊,終究還是要仰賴 HTTP 這個無狀態的協定;在 HTTP 規範中有定義了一系列的 Request Method(HTTP Method),其中較常用到的如下:

方法用途
GET取得資源
HEADGET 同為取得資源,但只取回 Header
POST提交資源
PUT取代指定資源
PATCH修改指定資源
DELETE刪除指定資源
OPTION詢問與指定資源的溝通方法

在規範中也提到,不同的 Method 指的是對同一件事情做不同的操作,並透過語意化的(semantic)Methods,讓不同的操作結果得以被預期。

GETPOST 相信絕大多數的開發者都不陌生,這是 HTML 的 <form action="..."> 唯二支援的 Methods;GET 是最頻繁使用的,無論是取得頁面、資料,一般而言都會使用 GETPOST 則常用在新增資源,但由於前述的 HTML <form action="..."> 不支援其他 Methods,在傳統網站中可能會用 POST 處理除了取得資料以外的所有事情。

PUTPATCH 通常都用在更新資源,兩者的差異是 PUT 預期的行為會是取代整個資源,而 PATCH 則是更新部分資源;把兩者對應到生活化案例的話,例如在餐廳吃飯,整桌重新點菜是 PUT,另外加點則會是 PATCH

DELETE 通常用在刪除資源;HEADGET 同樣為取回資源,但只取回 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 在規範中也有提到要如何正確使用,如果開發者沒有依照規範,確實是會造成影響的。

快取#

例如網頁快取,瀏覽器預設行為會對 GETHEAD 這兩個方法做快取,如果像標題說的取資料不是透過 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