#### Representational State Transfer
表述性狀態轉移
REST(Representational State Transfer表述性狀態轉移)是一種針對網絡應用的設計和開發方式,可以降低開發的復雜性,提高系統的可伸縮性。
REST提出了一些設計概念和準則:
1. 網絡上的所有事物都被抽象為資源(resource);
2. 每個資源對應一個唯一的資源標識(resource identifier);
3. 通過通用的連接器接口(generic connector interface)對資源進行操作;
4. 對資源的各種操作不會改變資源標識;
5. 所有的操作都是無狀態的(stateless)。
對于當今最常見的網絡應用來說,`resource identifier`是`url`,`generic connector interface`是`HTTP`,第4條準則就是我們常說的url不變性。這些概念中的`resouce`最容易使人產生誤解。`resouce`所指的并不是數據,而是`數據+特定的表現形式`(representation),這也是為什么REST的全名是`Representational State Transfer`的原因。
舉個例子來說,“本月賣得最好的10本書”和“你最喜歡的10本書”在數據上可能有重疊(有一本書即賣得好,你又喜歡),甚至完全相同。但是它們的representation不同,因此是不同的resource。
REST之所以能夠簡化開發,是因為其引入的架構約束,比如Rails 1.2中對REST的實現默認把controller中的方法限制在7個:index、show、new、edit、create、update和 destory,這實際上就是對CURD的實現。
更進一步講,Rails(也是當今大部分網絡應用)使用HTTP作為`generic connector interface`,HTTP則把對一個url的操作限制在了4個之內:`GET`、`POST`、`PUT`和`DELETE`。
REST之所以能夠提高系統的可伸縮性,是因為它強制所有操作都是stateless的,這樣就沒有context的約束,如果要做分布式、做集群,就不需要考慮context的問題了。同時,它令系統可以有效地使用pool。
REST對性能的另一個提升來自其對client和server任務的分配:server只負責提供resource以及操作resource的服務,而client要根據resource中的data和representation自己做render。這就減少了服務器的開銷。
既然REST有這樣的好處,那我們應該做什么呢?
我覺得我們應該思考兩個問題:
1. 如何使用REST;
2. REST和MVC的關系。
第一個問題假設REST是我們應該采用的架構,然后討論如何使用;第二個問題則要說明REST和當前最普遍應用的MVC是什么關系,互補還是取代?
我們先來談談第一個問題,如何使用REST。我感覺,REST除了給我們帶來了一個嶄新的架構以外,還有一個重要的貢獻是在開發系統過程中的一種新的思維方式:通過url來設計系統的結構。根據REST,每個url都代表一個resource,而整個系統就是由這些resource組成的。因此,如果url是設計良好的,那么系統的結構就也應該是設計良好的。對于非高手級的開發人員來說,考慮一個系統如何架構總是一個很抽象的問題。敏捷開發所提倡的Test Driven Development,其好處之一(我覺得是最大的好處)就是可以通過testcase直觀地設計系統的接口。比如,在還沒有創建一個class的時候就編寫一個testcase,雖然設置不能通過編譯,但是testcase中的方法調用可以很好地從class使用者的角度反映出需要的接口,從而為 class的設計提供了直觀的表現。這與在REST架構中通過url設計系統結構非常類似。雖然我們連一個功能都沒有實現,但是我們可以先設計出我們認為合理的url,這些url甚至不能連接到任何page或action,但是它們直觀地告訴我們:系統對用戶的訪問接口就應該是這樣。根據這些url,我們可以很方便地設計系統的結構。
讓我在這里重申一遍:REST允許我們通過url設計系統,就像`Test Driven Development`允許我們使用`testcase`設計`class接口`一樣。
url有這樣的好處,那我們就著重討論一下如何設計url。
網絡應用通常都是有 hierarchy 層級的,像棵大樹。我們通常希望url也能反映出資源的層次性。
比如對于一個blog應用:/articles表示所有的文章, /articles/1表示id為1的文章,這都比較直觀。遺憾的是,網絡應用的資源結構永遠不會如此簡單。因此人們常常會問這樣一個問題:
RESTful的url能覆蓋所有的用戶請求嗎?比如,login如何RESTful?search如何RESTful?
從REST的概念上來看,所有可以被抽象為資源的東東都可以使用RESTful的url。因此對于上面的兩個問題,如果login和search可以被抽象為資源,那么就可以使用RESTful的url。
search比較簡單,因為它只需要顯示搜索結果,返回的搜索結果,可以被抽象為資源,那么實現index方法就可以了。然而:search的關鍵字如何傳給server?index方法顯然應該使用HTTP GET,如果把關鍵字加到url后面,不符合REST的風格。
要解決這個問題,可以把每次search看作一個資源,因此要創建create和 index方法,create用來在用戶點擊“搜索”按鈕是通過HTTP POST把關鍵字傳給server,然后index則用來顯示搜索結果。這樣一來,我們還可以記錄用戶的搜索歷史。
使用同樣的方法,我們也可以對 login應用REST,即每次login動作是一個資源。
現在,我們來看復雜一些的東東。如何用url表達“category為ruby的 article”?一開始可能想到的是/category/ruby/articles,這種想法很直觀。但是我覺得里面的category是不需要的,我們可以直接把“/ruby”理解為“category是ruby”,也就是說“ruby”出現的位置說明了它指的就是category。OK, /ruby/articles,單單從這個url上看,我們能獲得多少關于category的信息呢?顯然category隱藏在了url后面,這樣做到底好不好,應該是仁者見仁,智者見智了。對于如何表達category這樣的東西,我還沒想出很好的方式,大家有什么好idea,可以一起討論。
另外還有一種url形式,它對應到程序中的繼承關系。比如product是一個父類,book和computer是其子類。那么所有產品的url應該是/products,所有書籍的url應該是/books,所有電腦的url應該是 /computers。這一想法就比較直觀了,而且再次驗證了url可以幫助我們進行設計的論點。
> 讓我再說明一下我的想法:如果每個用戶需求都可以抽象為資源,那么就可以完全使用REST。
由此看來,使用REST的關鍵是如何抽象資源,抽象得越精確,對REST的應用就越好。
因此,如何改變我們目前根深蒂固的基于action的思想是最重要的。
有了對第一個問題的討論,第二個問題就容易討論多了。REST會取代MVC嗎?還是彼此是互補關系(就像AOP對于OOP)?答案是It depends!如果我們可以把所有的用戶需求都可以抽象為資源,那么MVC就可以推出歷史的舞臺了。如果情況相反,那么我們就需要混合使用REST和 MVC。
當然,這是非常理想的論斷。可能我們無法找到一種方法可以把所有的用戶需求都抽象為資源,因為保證這種抽象的完整性(即真的是所有需求都可以)需要形式化的證明。而且即使被證明出來了,由于開發人員的能力和喜好不同,MVC肯定也會成為不少人的首選。但是對于希望擁抱REST的人來說,這些都沒有關系。只要你開發的系統所設計的問題域可以被合理地抽象為資源,那么REST就會成為你的開發利器。
- 《Restful Web Service Cookbook》
- 簡介
- 推薦序
- 第 1 章 使用統一接口
- 1.1 如何保持交互的可見性
- 1.2 何時使用 GET 方法
- 1.3 何時使用 POST 方法
- 1.4 如何使用 POST 方法創建資源
- 目錄
- PHP RESTful
- 理解RESTful架構
- 深入淺出REST
- 表述性狀態轉移
- 無狀態
- 設計指南
- RESTful API 設計指南
- RESTful API 設計最佳實踐
- 測試工具
- soapUI
- 實例
- 豆瓣
- 應用
- 接口規范
- 視頻
- 《Restful API實戰》
- 課程目標
- 第1章 Restful是什么
- 1-1 restful簡介及資源介紹
- 第2章 為什么要使用Restful
- 2-1 Restful中HTTP協議介紹
- 2-2 架構區別
- 第3章 如何使用Restful
- 3-1 restful設計要素
- 3-2 DHC Client
- 3-3 本地開發環境搭建
- 3-4 確認設計要素
- 3-5 數據庫設計
- 3-6 用戶業務邏輯
- 3-7 文章業務邏輯
- 3-8 restfulApi設計要素
- 3-9 初始化運行參數
- 3-10 完善用戶API
- 3-11 完善文章API
- 文摘
- RESTful 接口實現簡明指南
- RESTful Web 服務教程
- 模型表示(Representations)
- 資源定位
- URI中的查詢參數
- 統一接口
- PUT 和 POST 的區別
- 基于 REST 的 Web 服務
- PHP Reatful
- Restful狀態響應碼
- 《REST API 安全設計指南》