Representational State Transfer,簡稱 REST。是 Roy Fielding 博士在2000年他的博士論文中提出來的一種軟體架構風格。目前是一種相當風行的 Web Services 實現手法,因為 REST 風格的 Web Services 遠比傳統的 SOAP 與 XML-RPC 來的簡潔。在近年,幾乎所有各大主流網站的 API 都已採用此種風格進行設計。
REST 提出了一些設計概念和準則:
對照到 web services 上來說:
RESTful Web Services 是使用 HTTP 並遵循 REST 設計原則的 Web Services。它從以下三個方面資源進行定義:
以下列出在實現 RESTful Web 服務時HTTP請求方法的典型用途。
資源 | GET |
---|---|
一組資源的URI,比如http://example.com/resources/ | 使用給定的一組資源替換當前整組資源。 |
單個資源的URI,比如http://example.com/resources/142 | 獲取 指定的資源的詳細信息,格式可以自選一個合適的 media type(如:XML、JSON等) |
資源 | PUT |
---|---|
一組資源的URI,比如http://example.com/resources/ | 列出 URI,以及該資源組中每個資源的詳細信息(後者可選)。 |
單個資源的URI,比如http://example.com/resources/142 | 替換/創建 指定的資源。並將其追加到相應的資源組中。 |
資源 | POST |
---|---|
一組資源的URI,比如http://example.com/resources/ | 在本組資源中創建/追加一個新的資源。 該操作往往返回新資源的URL。 |
單個資源的URI,比如http://example.com/resources/142 | 把指定的資源當做一個資源組,並在其下創建/追加一個新的元素,使其隸屬於當前資源。 |
資源 | DELETE |
---|---|
一組資源的URI,比如http://example.com/resources/ | 刪除 整組資源。 |
單個資源的URI,比如http://example.com/resources/142 | 刪除 指定的元素。 |
DHH 在 Discovering a world of Resources on Rails 提到一個核心概念:Constraints are liberating 。
很多剛踏入 Rails 這個生態圈的開發者,對於 REST 總有股強烈的反抗心態,認為 REST 是一個討厭的限制。但事實上,DHH 卻認為引入 REST 的制約卻反為 Rais 開發帶來了更大的解放,而這也是他引入這個設計的初衷。
在傳統的開發方式中,對於有效組織網頁應用中的程式碼,大家並沒有什麼共識。所以很可能在專案中會出現這種風格不一致的程式碼:
def add_friend
end
def remove_friend
end
def create_post
end
def delete_post
end
透過 REST 的包裝(對於 resource 的操作),可以變得更簡潔直觀,且具有統一的寫法。
class FriendShipController
def create
end
def destroy
end
end
class PostController
def create
end
def destroy
end
end
大眾最常對 REST 產生的一個誤解,就是以為 resource 只有指的是 data。其實 resource 指的是:data + representation (表現形式,如 html, xml, json 等)。
在網頁開發中,網站所需要的表現格式,不只有 HTML 而已,有時候也需要提供 json 或者 xml。Rails 透過 responder 實現了
在 Resource Oriented Architecture (ROA,一組 REST 架構實現 guideline) 中有一條: 「A resource can use file extension in the URI, instead of Content-Type negotiation 」。
Rails 透過 responder 的設計,讓一個 action 可以以 file extension ( .json, .xml, .csv ...etc.) 的形式,提供不同類型的 representation。
class PostsController < ApplicationController
# GET /posts
# GET /posts.xml
def index
@posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @posts }
end
end
REST 之所以能簡化開發,是因為其所引入的架構約束。Rails 中的 REST implementation 將 controller 的 method 限制在七個:
實際上就是整個 CRUD。而在實務上,web services 的需要的操作行為,其實也不脫這七種。Rails 透過 HTTP 作為 generic connector interface,使用 HTTP 的四種 verb : GET、POST、PUT、DELETE 對資源進行操作。
<%= link_to("List", posts_path) %>
<%= link_to("Show", post_path(post)) %>
<%= link_to("New", new_post_path) %>
<%= link_to("Edit", edit_post_path(post)) %>
<%= form_for @post , :url => posts_path , :html => {:method => :post} do |f| %>
<%= form_for @post , :url => post_path(@post) , :html => {:method => :put} do |f| %>
<%= link_to("Destroy", post_path(@post), :method => :delete )
Rails 的表單欄位,是對應 Model Attribute 的:
<h1>New post</h1>
<%= form_for @post , :url => posts_path do |f| %>
<%= f.error_messages %>
<div><label>subject</label><%= f.text_field :subject %></div>
<div><label>content</label><%= f.text_area :content %> </div>
<%= f.submit "Submit", :disable_with => 'Submiting...' %>
<% end -%>
<%= link_to 'Back', posts_path %>
透過 form_for 傳送出來的表單,會被壓縮包裝成一個 parameter: params[:post],
def create
@post = Post.new(params[:post])
if @post.save
flash[:notice] = 'Post was successfully created.'
redirect_to post_path(@post)
else
render :action => "new"
end
end
如此一來,原本創造新資源的一連串繁複動作就可以大幅的被簡化,開發速度達到令人驚艷的地步。