現代的網站越來越多前後端分離的架構,透過 前端 MVC 框架 快速堆砌出 SPA,再透過 API 取得變動的資料也已經是開發者日常;而用來聯繫前後端的 API,其重要性自然也就不言而喻了。身為一個前端開發者,認識後端的 API 設計方式也是很重要的一環,今天就讓我們針對 API 設計來一探究竟吧!
本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您 前往購買 支持!
畢竟是網站的前後端,其中間的通訊,終究還是要仰賴 HTTP 這個無狀態的協定;在 HTTP 規範中 有定義了一系列的 Request Method,其中較常用到的如下:
GET
同為取得資源,但只取回 Header在規範中也提到,不同的 Method 指的是對同一件事情做不同的操作,並透過語意化的(semantic)Methods,讓不同的操作結果得以被預期。
GET
、POST
相信絕大多數的開發者都不陌生,這是 HTML 的 <form action="...">
唯二支援的 Methods;GET
是最頻繁使用的,無論是取得頁面、資料,一般而言都會使用GET
,POST
則常用在新增資源,但由於前述的 HTML <form action="...">
不支援其他 Methods,在傳統網站中可能會用 POST
處裡除了取得資料以外的所有事情。
關於為什麼 HTML 不支援其他 HTTP Methods,可以參考 這則問答,及 這則 Issue 討論。
PUT
和 PATCH
通常都用在更新資源,兩者的差異是 PUT
預期的行為會是取代整個資源,而 PATCH
則是更新部分資源;把兩者對應到生活化案例的話,例如在餐廳吃飯,整桌重新點菜是 PUT
,另外加點則會是 PATCH
。
DELETE
通常用在刪除資源;HEAD
與 GET
同樣為取回資源,但只取回 Header,通常會用在測試資源是否存在;OPTION
是詢問這個資源應該要怎麼獲取,常在 發送 CORS 的預檢(preflight)請求 時使用。
當然,目前講的都是規範提到且較建議的一般用法,實際伺服器的 API 怎麼開依然是看實作者;但透過語意化的 Methods 設計 API,絕對可以讓 API 對開發者更加友善。
前述的只是規範,而且只圍繞在 HTTP Methods 上;有沒有更完整的實作方法建議呢?
當然有囉,就是大家耳熟能詳的 RESTFul API;由 Roy Fieldin 在 IEFT 開發 HTTP 標準的六年間持續專研、驗證,並在 2000年 於博士論文 《Architectural Styles and the Design of Network-based Software Architectures》 中所提出,是一種網路程式的設計風格;這邊的 REST 是 表現層狀態轉換(Resource Representational State Transfer) 的縮寫,簡單說就是透過動詞(HTTP Methods)、名詞(URI/URL,代表目標資源)、內容型態(回應的內容,HTML、XML、JSON、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
回應的結果。
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 做了簡短的介紹,希望以上內容能幫助到讀者您。
本文就到這邊啦,如果文中有任何錯誤,或是說明不清楚的地方,都歡迎您於底下留言回應喔!
筆者
Gary
半路出家網站工程師;半生熟的前端加上一點點的後端。
喜歡音樂,喜歡學習、分享,也喜歡當個遊戲宅。相信一切安排都是最好的路。
對於舉例的那一段有點小疑問:
[GET] http://mytube.com/v1/video/ -> 取得 video 列表
[POST] http://mytube.com/v1/video/MgphHyGgeQU -> 新增 video
[GET] http://mytube.com/v1/video/MgphHyGgeQU -> 取得指定 ID 的 video
[PUT] http://mytube.com/v1/video/MgphHyGgeQU -> 修改指定 ID 的 video
[DELETE] http://mytube.com/v1/video/MgphHyGgeQU -> 刪除指定 ID 的 video
先講一下我沒有看原始論文,所以不確定是不是原始論文就是這樣寫還是寫錯XD
你是對的 我寫的時候沒改好XD
感謝糾正
感謝分享 內容幾乎是面試必考題了阿! 以前都只會參考 API 文件接都沒好好想過為什麼用 put 或 patch
哈哈~我以前是只會用 GET & POST,而且還全部都導去同一個函式處理;後來換工作才知道原來還有其他方法 XD
謝謝支持