淺談 REST 軟體架構風格 (Part.II) - 如何設計 RESTful Web Service?


如何設計 RESTful Web Service

在前一篇文章(淺談 REST 軟體架構風格 (Part.I) – 從了解 REST 到設計 RESTful!)中已經與大家介紹 REST 的基本概念,或許各位對 REST 可能還是略懂略懂。這篇文章主要的用意是藉由我們現在 (似乎) 熟悉的 HTTP 為基礎,來說明如何設計比較 RESTful 的 Web Service。

那什麼是 RESTful Web Service?就是實作 REST 的 Web Service。但是有人問,Web Service 所使用的 HTTP 不就是 REST 的實作了嗎?為何還要設計 RESTful Web Service呢?答案很簡單,因為某些 Web Service 在設計上只是把 HTTP 當做連線媒介,並沒有真正使用到 HTTP 關於 REST 的設計,雖然在這樣的情況下設計出來的 Web Service 絲乎頗有彈性、也很強大,但是卻違背了 HTTP(REST架構)的設計理念,或者再次在 HTTP 上頭實作了跟 HTTP 一樣的功能。總而言之,善用 HTTP 進行設計就對了,別把問題變複雜了。

Web Service 返樸歸真

首先我們先來看看傳統的 Web Service 可能都是怎麼設計的。假設我們要實作書籍管理 Web Service,需求為書籍的基本 CRUD (Create, Read, Update and Delete),那麼可能設計的規格如下:

Web Service 網址:http://book.com/books,操作 Web Service 時使用 HTTP Post XML 到 Web Service 網址。然後伺服器會回傳執行結果的 XML,如下所示:

操作 Web Service 的規格如下 (CRUD):





Web Service 規格設計好了,我們來看看。上述的規格擁有一致性的 XML 回傳格式,容易封裝資料,然而 XML 的格式也相當簡潔,使用 <action> 來描述動作非常直覺,真是無懈可擊,太完美了,這應該就是上帝的傑作!

嗯....... 當了解 REST 後再看到這樣的設計,我總會想起 How I Explained REST to My Wife 這篇文章中的一段話:

Ryan: Sadly, no. Instead, the large majority are busy writing layers of complex specifications for doing this stuff in a different way that isn’t nearly as useful or eloquent. Nouns aren’t universal and verbs aren’t polymorphic. We’re throwing out decades of real field usage and proven technique and starting over with something that looks a lot like other systems that have failed in the past. We’re using HTTP but only because it helps us talk to our network and security people less. We’re trading simplicity for flashy tools and wizards.

譯:很遺憾,大多數的人為了達到同樣的目標,忙著用不同的方法去設計出複雜且不易使用的規格。不但名詞 (Nouns) 不通用,且動詞 (Verbs) 也不多態。我們拋棄了過去幾十年的失敗經驗,再度重蹈覆轍。我們使用 HTTP 不僅僅是幫助我們使用網路,而我們卻忽略了 HTTP 初衷簡單化 (Simplicity) 的設計理念,得到的卻是華而不實而絢麗的工具。

除了上述自訂的 Web Service 規格之外,當然還有其他常用 Web Service 標準,例如 SOAP 與 XML-RPC 等等。這些規格在設計上,相較於 RESTful Web Service 看起來總是複雜了許多。

好的,請先忘記剛剛的設計,讓我們來設計 RESTful Web Service 吧。我們先來看看 REST Triangle (左圖) 裡面的項目:

  • Nouns - 名詞
    為 Resources (資源) 定義唯一的識別,在 HTTP 中我們借用 URI 為資源進行識別定義,範例:http://book.com/books/{isbn}
  • Verbs - 動詞
    使用一組有限的動詞對資源進行操作,在 HTTP 中使用 GET, POST, PUT, DELETE 來操作資源。很多人只有聽過 GET 與 POST,甚至不知道 HTTP 有這些 Method 可以使用,其實在 HTTP 1.1 (RFC 2616) 中的 Method Definitions 這個章節裡有提到,HTTP Method 總共定義了以下八種:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT。然而我們在設計 RESTful 的時候,選用了四種比較多態性的 Method 作為動詞。
  • Content types - 格式
    REST 所謂的 Representation,在 HTTP 中就是 Header 所送出的 Content-type,然而 Content-type 是使用 MIME Types 進行定義。

讓我們重新整理一下剛剛設計的 Web Service,改用比較接近 HTTP 且 RESTful 的方式進行設計,如下:

功能 URI HTTP Method Request Response Status Code
新增 http://book.com/books POST <book />... void 200|400
刪除 http://book.com/books/{isbn} DELETE void void 200|400|404
修改 http://book.com/books/{isbn} PUT <book />... void 200|400|404
查詢 http://book.com/books/{isbn} GET void <book />... 200|400|404
列表 http://book.com/books GET void <books />... 200|400|404

 

上述的規格,我們盡可能地善用 HTTP 已經擁有的能力來進行設計。採用 POST, GET, PUT, DELETE 來對應資料的 CRUD 操作,其中 Web Service 的處理狀態碼也直接採用 HTTP Status Code (可參考 RFC 2616 Status Code Definitions 這一個章節),也很容易依循標準定義出更多元化的狀態碼,甚至回傳訊息也能夠輕易地實現,不必煩惱數字與狀態之間的對應關係。如此一來,RESTful Web Service 看起來是不是更加簡潔了呢?

其實「設計 RESTful Web Service 的要訣只是盡可能使用 HTTP 既有的能力」罷了,至於要用到什麼程度,這也要考慮實作構面的因素。過於 RESTful 也不見得是最實用的設計,像是保留 Cookie 的機制用來驗證登入身分,在實作上是比較可行的。而當我們碰到某些需求不容易用 REST 操作資源的概念來詮釋時,也只能將設計合理化,盡可能向著 HTTP 靠近。

Reference

SlideShare

Facebook 留言

廣告

樂樂童鞋