表現層狀態轉換

表現層狀態轉換（Representational State Transfer，縮寫：REST）是羅伊·菲爾丁博士於2000年在他的博士論文中提出來的一種全球資訊網軟體架構風格，目的是便於不同軟體/程序在網路（例如網際網路）中互相傳遞資訊。表現層狀態轉換根基於超文本傳輸協議，是一種軟體架構。符合或相容於這種架構風格（簡稱為 REST 或 RESTful）的網路服務，使用者端在發出存取和操作網路資源的請求時可以發出統一資源標識符。表現層狀態轉換提供了在網際網路的計算系統之間，彼此資源可交互使用的協作性質（interoperability）。相對於其它種類的網路服務，例如SOAP服務，則是以本身所定義的操作集，來存取網路上的資源。

目前在三種主流的Web服務實現方案中，因為REST模式與複雜的SOAP和XML-RPC相比更加簡潔，越來越多的Web服務開始採用REST風格設計和實現。例如，Amazon.com提供接近REST風格的Web服務執行圖書查詢；雅虎提供的Web服務也是REST風格的。

## 要點及標準

需要注意的是，REST是設計風格而不是標準。REST通常基於HTTP、URI、XML以及HTML這些現有的廣泛流行的協議和標準。

- 資源是由URI來指定。
- 對資源的操作包括獲取、創建、修改和刪除，這些操作正好對應HTTP協議提供的GET、POST、PUT和DELETE方法。
- 通過操作資源的表現形式來操作資源。
- 資源的表現形式則是XML或者HTML，取決於讀者是機器還是人、是消費Web服務的客戶軟體還是Web瀏覽器。當然也可以是任何其他的格式，例如JSON。

### 可重新表達的狀態遷移的特徵

- Uniform Interface：統一接口。
- 以資源為基礎每個資源都可以通過URI訪問到。也就是一個個可以認知的資源，比如文檔，音樂，影片等資訊，都可以通過唯一的URI確定。
- 通過重表達的客戶端可以管理原資源就是我們通過客戶端可以修改原資源的狀態。
- 返回資訊足夠描述自己這樣重表達的客戶端可以知道如何處理。
- 超媒體是應用狀態的引擎處理以超媒體為基礎的狀態變化。
- Stateless：無狀態。
- Cacheable：可緩存。
- Client-Server：客戶伺服器分離模式，任何一個客戶端與伺服器都是可替換的。
- Layered System：分層的系統，客戶端不知道他聯繫的是不是最終伺服器。
- Code on Demand（可選）：伺服器可以將能力擴展到客戶端，如果客戶端可以執行的話。這個功能是可選擇的。

### REST架構的限制條件

REST架構風格最重要的架構限制有6個：

- 客戶端-伺服器（Client-Server）
- 客戶端-伺服器結構限制的目的是將客戶端和伺服器端的關注點分離。將使用者界面所關注的邏輯和數據存儲所關注的邏輯分離開來有助於提高使用者界面的跨平台的可移植性。通過簡化伺服器模塊也有助於伺服器模塊的可擴展性。
- 無狀態（Stateless）
- 伺服器不能保存客戶端的資訊；每一次從客戶端發送的請求中，要包含所有的必須的狀態資訊，會話資訊由客戶端保存，伺服器端根據這些狀態資訊來處理請求。
- 伺服器可以將會話狀態資訊傳遞給其他服務，比如資料庫服務，這樣可以保持一段時間的狀態資訊，從而實現認證功能。
- 當客戶端可以切換到一個新狀態的時候發送請求資訊。
- 當一個或者多個請求被發送之後，客戶端就處於一個狀態變遷過程中。每一個應用的狀態描述可以被客戶端用來初始化下一次的狀態變遷。
- 緩存（Cacheability）
- 如同全球資訊網一樣，客戶端和中間的通訊傳遞者可以將回覆緩存起來。回覆必須明確的或者間接的表明本身是否可以進行緩存，這可以預防客戶端在將來進行請求的時候得到陳舊的或者不恰當的數據。管理良好的緩存機制可以減少客戶端-伺服器之間的交互，甚至完全避免客戶端-伺服器交互，這進一步提了高性能和可擴展性。
- 統一接口（Uniform Interface）
- 這是 RESTful 系統設計的基本出發點。它簡化了系統架構，減少了耦合性，可以讓所有模塊各自獨立的進行改進。包括下列四個限制：
- 請求中包含資源的 ID（Resource identification in requests）請求中包含了各種獨立資源的標識，例如，在Web服務中的URI。資源本身和發送給客戶端的標識是獨立。例如，伺服器可以將自身的資料庫資訊以HTML、XML或者JSON的方式發送給客戶端，但是這些可能都不是伺服器的內部記錄方式。
- 資源通過標識來操作（Resource manipulation through representations）當客戶端擁有一個資源的標識，包括附帶的元數據，則它就有足夠的資訊來刪除這個資源。
- 消息的自我描述性（Self-descriptive messages）每一個消息都包含足夠的資訊來描述如何來處理這個資訊. 例如，媒體類型 (media-type) 就可以確定需要什麼樣的分析器來分析媒體數據.
- 用超媒體驅動應用狀態（Hypermedia as the engine of application state (HATEOAS)）同使用者訪問Web伺服器的Home頁面相似，當一個 REST 客戶端訪問了最初的REST應用的URI之後，REST 客戶端應該可以使用伺服器端提供的連結，動態的發現所有的可用的資源和可執行的操作。隨著訪問的進行，伺服器在響應中提供文字超連結，以便客戶端可以得到當前可用的操作。客戶端無需用確定的編碼的方式記錄下伺服器端所提供的動態應用的結構資訊。
- 分層系統（Layered System）
- 客戶端一般不知道是否直接連接到了最終的伺服器，或者是路徑上的中間伺服器。中間伺服器可以通過負載均衡和共享緩存的機制提高系統的可擴展性，這樣可也便於安全策略的部署。
- 按需代碼（Code-On-Demand，可選）
- 伺服器可以通過發送可執行代碼給客戶端的方式臨時性的擴展功能或者定製功能，例如Java Applet、Flash或JavaScript。

### 關於狀態

應該注意區別應用的狀態和連接協議的狀態。HTTP連接是無狀態的（也就是不記錄每個連接的資訊），而REST傳輸會包含應用的所有狀態資訊，因此可以大幅降低對HTTP連接的重複請求資源消耗。

### 應用於Web服務

符合REST設計風格的Web API稱為RESTful API。它從以下三個方面資源進行定義：

- 直觀簡短的資源地址：URI，比如：`http://example.com/resources`。
- 傳輸的資源：Web服務接受與返回的網際網路媒體類型，比如：JSON，XML，YAML等。
- 對資源的操作：Web服務在該資源上所支持的一系列請求方法（比如：POST，GET，PUT或DELETE）。

下表列出了在實現RESTful API時HTTP請求方法的典型用途。

資源｜GET｜PUT｜POST｜DELETE

一組資源的URI，比如`https://example.com/resources`｜列出URI，以及該資源組中每個資源的詳細資訊（後者可選）。｜使用給定的一組資源替換當前整組資源。｜在本組資源中創建/追加一個新的資源。該操作往往返回新資源的URL。｜刪除整組資源。

單個資源的URI，比如`https://example.com/resources/142`｜獲取指定的資源的詳細資訊，格式可以自選一個合適的網路媒體類型（比如：XML、JSON等）｜替換/創建指定的資源。並將其追加到相應的資源組中。｜把指定的資源當做一個資源組，並在其下創建/追加一個新的元素，使其隸屬於當前資源。｜刪除指定的元素。

PUT和DELETE方法是冪等方法。GET方法是安全方法（不會對伺服器端有修改，因此當然也是冪等的）。

不像基於SOAP的Web服務，RESTful Web服務並沒有「正式」的標準。這是因為REST是一種架構，而SOAP只是一個協議。雖然REST不是一個標準，但大部分RESTful Web服務實現會使用HTTP、URI、JSON和XML等各種標準。

## 實現舉例

例如，一個簡單的網路商店應用：

```
GET http://www.store.com/products
```

```
GET http://www.store.com/products/12345
```

- 下單購買：POST http://www.store.com/orders ...

## REST的優點

- 可更高效利用快取來提高響應速度
- 通訊本身的無狀態性可以讓不同的伺服器的處理一系列請求中的不同請求，提高伺服器的擴展性
- 瀏覽器即可作為客戶端，簡化軟體需求
- 相對於其他疊加在HTTP協議之上的機制，REST的軟體相依性更小
- 不需要額外的資源發現機制
- 在軟體技術演進中的長期的相容性更好

## 實現

- Ruby on Rails1.2以後的版本支持 REST model。
- JBoss RESTEasyJBoss的REST實現
- Node.js RESTful APINode.js實現RESTful API
- Learn REST: A RESTful Tutorial

## 參考文獻

### 來源

- Roy Thomas Fielding的博士論文「Architectural Styles and the Design of Network-based Software Architectures」
- Paul Prescod. 第二代web服務