什麼是 RESTful API?路由語義化設計教學

什麼是 REST?

REST 是 Representational State Transfer 的縮寫,可譯為「具象狀態傳輸」。由 Roy Fielding 博士在 2000 年的博士論文中所提出。他同時也是 HTTP 規範的主要作者之一。符合 REST 風格的網站架構可以稱為 RESTful。

REST 是一種軟體架構風格(並非標準),目的是幫助在世界各地不同軟體、程式在網際網路中能夠互相傳遞訊息。每一個網頁都可視為一個資源(resource)提供使用者使用,而你可以透過 URL(Uniform Resource Locator),也就是這些資源的地址,來取得這些資源並在你的瀏覽器上使用。

RESTful API 的特性

  • 無狀態(Stateless):每一個請求都是獨立的,服務器不會儲存任何請求的狀態。
  • 客戶端-服務器(Client-Server):客戶端負責用戶交互,服務器負責存儲和處理資料。兩者相互獨立,方便進行分開維護或擴展。
  • 可緩存(Cacheable):響應中的資料能夠被客戶端緩存,提高性能。
  • 分層系統(Layered System):可以使用代理伺服器進行轉發,或提供安全性控制等。
  • 統一介面(Uniform Interface):API 的設計要盡可能簡單且一致。

為什麼要認識 REST?

當 Roy Fielding 最一開始在打造人們今天所看到的網際網路的時候,其中最大的一個問題是:要如何跟世界各地的任何一台電腦溝通?因此有了 REST 的出現。然而這個問題在現今經常被忽略,甚至人們會覺得 REST 是一個新的概念,但其實在最初 HTTP 誕生的時候,REST 就也跟著問世了。電腦溝通的方法與規則其實很簡單,就像人們平時使用的文法一樣,在這裡電腦使用的是 HTTP 動詞(Verb),列舉如下:

RESTful API 的路由語義化設計

在 RESTful API 設計中,通常使用 HTTP 方法來定義對資源的操作,並使用路徑(URI)來表示資源。這種設計方式使得 API 路由更具語義化,易於理解和使用。

  • GET 讀取資源
  • PUT 替換資源
  • PATCH 更換資源部分內容
  • DELETE 刪除資源
  • OPTIONS 回傳該資源所支援的所有 HTTP 請求方法
  • CONNECT 將連線請求轉換至 TCP/IP 隧道
  • POST 新增資源

在透過 URL 對特定資源請求動作的時候,首先你要知道你的意圖。用日常生活的語言來說,URL 就好比是一個物品,譬如「杯子」,當你想要對這個「杯子」做點動作、而又必須請人幫忙的時候,你就得明確的說出想對那個杯子進行的動作,表明你的意圖,這樣他人才能順利幫你完成工作,像是「拿杯子」、或是「丟杯子」。在網際網路上也是一樣,只是這裡你將使用電腦可以理解的語言,像是 “GET” this URL 或是 “DELETE” this URL。

若想透過網際網路,跟其他電腦(伺服器)取得資訊,就得使用 HTTP 動詞 “GET”,若想要增加資訊,就使用 “POST”,若想要更新資訊就使用 “PUT”。到這裡,你已經了解到電腦是如何透過共通的語言,在網際網路上進行溝通。

Router, Routing, Route

在談網路基礎建設時,路由器 (router) 是某種實體設備,負責幫每個資料封包 (packet) 選擇傳輸路徑,扮演類似交通指揮的角色。而「路由器幫資料封包們選擇路徑,引導資料按指定路徑移動」的這個過程,被稱為「routing」。

Web 開發裡的路由

轉移到 web app 網路應用程式開發的領域,路由不再是實體設備,而是指 URL 的處理程序。這組處理程序會把 HTTP 動詞、URL、和相關的程式碼連接起來。

我們會在路由系統裡,定義「收到什麼 HTTP request,就執行什麼動作」。

舉例來說,如果今天收到一支 HTTP request,格式為 GET http://www.example.com/todos,路由系統會調度出對應的資源,也就是和「瀏覽全部待辦事項」相關的樣板、邏輯、資料等等。

因為有了路由系統,網站對外開放的網址,不需要對應到實際的專案目錄。

Express.js 與路由

Web 開發框架通常會內建路由系統,學習框架的第一件事,就是要學習如何使用框架提供的路由系統。

在以下的程式碼片段中,我們設定了一條路由:

router.get(‘/about’, function (req, res) {
// do something
})

這條路由的意思是,如果收到符合 GET /about 格式的 request,就會執行函式內容。

學習後端開發 Node.js Express.js框架

如何設計路由?

我們會採用一套 REST 的架構風格來設計路由,RESTful 的設計以「資源」為中心,再搭配 HTTP method 的動詞,以及 CRUD 等資料操作:

對資料的操作,不外乎:新增 (create)、讀取 (read)、更新 (update)、刪除 (delete) 四種動作,通常會簡稱為 CRUD。

而 HTTP method 是有意義的動詞,如 GET、POST、PATCH、DELETE 等,因此 RESTful 的表意設計運用動詞的組合,來表達出對資源的操作方式。

例如我們看到 GET http://www.example.com/posts/1,就會立刻可以理解他要取得 www.example.com 網站中,編號 1、名為 posts 的資源。

路由語義化:RESTful 風格應用

什麼是 RESTful

運用 HTTP 來表達語義的路由設計風格稱為 RESTful API。所謂的 API 是應用程式介面 (application programming interface),網址也是一種應用程式的「介面」,故稱為 API。

(延伸閱讀:API是什麼?認識Web API、HTTP 和JSON 資料交換格式)

RESTful 風格的網址設計強調從路由結構就能看出要對什麼資料、進行什麼操作。舉例來說,如果資料是 todos,那麼 RESTful 風格的 CRUD 路由就會這樣寫:

restful http request

從網址上,你會看出要操作的資源叫做 todos,這邊習慣用複數名詞。然後固定結構是:

  • 瀏覽全部資料:GET + 資源名稱
  • 瀏覽特定資料:GET + 資源名稱 + :id
  • 新增一筆資料:POST + 資源名稱
  • 修改特定資料:PUT + 資源名稱 + :id
  • 刪除特定資料:DELETE + 資源名稱 + :id

總之,如果需要處理特定資料,就需要加上 :id,其他情況都用 HTTP 動詞來做變化。從網址上的複數名詞可以看出操作的對象,這就是 RESTful 的精神。

當然,一個專案裡不可能所有的路由都在操作資料,因此不會每條路由都能完美對齊 RESTful,例如「登入」的路由通常設定為 POST /login,就完全是以動詞為中心。身為專案的架構者,有時候還是需因地制宜,風格只是參考,不是阻礙。

總之,RESTful 這種「和 CRUD 對齊」的特性會帶來一些溝通的便利性,客戶端只需要知道可用資源,就能依照約定俗成的邏輯,推測出相關的 API。

這種「約定俗成」的設計感也可以讓工程師規劃路由時減少一些煩惱。

舉個例子,我們在專案中實際的配置可能是

RESTful 是一個非常流行的路由設計的參考風格,當然,在實際開發專案時,可能還是會有一些因時制宜的考量。

下圖對照了「完全採用 RESTful 風格」 和實際的路由規劃做對照,用 * 標記出了不同的地方。

restful 風格
  • new 頁面和 edit 頁面:這兩條路由並不是「對 todos 進行資料操作」,但也是很常出現的頁面。因為本質仍然是瀏覽,所以動詞用 GET,另外在 URL 加上 newedit 來表達功能屬性。
  • 首頁 v.s. 瀏覽全部路由:在這裡我們選擇著重了首頁的語義,因此只配置路由 GET /,而沒有配置 GET /todos

如果是部落格網站,可能會有叫做 posts 的資源,再搭配 HTTP 動詞和新增/瀏覽/修改/刪除等操作,就會出現如下變化:

RESTful 的網址變化很有規律,也很簡潔,因此近年有愈來愈多人採用 RESTful 設計風格來架構網站,(注意,它是風格,而不是標準,意思是偶爾出現特例沒關係)。

Restful API 設計教學

1. 理解REST原則

Restful API的設計遵循特定的原則:

  • 客戶端-服務端分離:客戶端和服務端應該獨立開發和部署,彼此之間僅通過請求來交互。
  • 無狀態:每次請求應該包含所有必要的信息,服務端不應該保存請求之間的狀態。
  • 可緩存:提供的資源應該標記為可緩存或不可緩存,以提高性能。
  • 統一接口:應使用標準的HTTP方法(如GET、POST、PUT、DELETE)來進行交互。
  • 分層系統:客戶端通常不能確定它是直接與終端服務器還是中間層服務器交互。

2. 資源識別

  • 使用URI定位資源:每個資源應該有一個唯一的URI。例如,/users代表用戶資源,/users/123代表ID為123的用戶。
  • 使用名詞定義資源:URI應該使用名詞來標識資源,而不是動詞。

3. 使用HTTP方法

  • GET:用於獲取資源,不應當改變服務端的狀態。
  • POST:用於創建新資源。
  • PUT:用於更新現有資源。
  • DELETE:用於刪除資源。

4. 狀態代碼的使用

  • 200 OK:請求成功。
  • 201 Created:成功創建了新資源。
  • 204 No Content:請求成功但沒有返回內容(常用於DELETE請求)。
  • 400 Bad Request:客戶端錯誤導致服務端無法處理請求。
  • 404 Not Found:請求的資源不存在。
  • 500 Internal Server Error:服務端錯誤。

5. 資源表述

  • 使用如JSON或XML等格式來表述資源。例如,當客戶端向/users發送GET請求時,服務端可以返回一個JSON格式的用戶列表。

6. 考慮安全性和認證

  • 使用HTTPS來加密數據。
  • 對於敏感數據,應實施適當的認證和授權機制。

7. 版本控制

  • 對API進行版本控制,以便於未來的擴展和維護。例如,使用/v1/users來表示第一版的用戶API。

8. 錯誤處理

  • 提供清晰的錯誤消息和代碼,幫助客戶端了解問題所在。

9. 文件和API探索性

  • 提供API的文檔,包括各種請求的用法和範例。
  • 考慮實現API探索性,允許用戶理解並使用API的結構。

通過遵循這些指導原則,開發者可以創建出清晰、高效且易於使用的Restful API,從而提升整個應用的可用性和可維護性。

延伸閱讀

三分鐘小測驗,找到你進階學習 Web App 開發的入口