1. 程式人生 > >如何給老婆解釋什麽是Restful【轉載】

如何給老婆解釋什麽是Restful【轉載】

形象 nta balance val 請求 term name 傳輸協議 咖啡廳

老婆經常喜歡翻看我訂閱的技術雜誌,她總能從她的視角提出很多有趣的問題。

一個悠閑的周日下午,她午覺醒來,又習慣性的抓起這個月的雜誌,饒有興趣地看了起來。

果不其然,看著看著,她又對我發難了,“Restful是什麽呀,老公?是restaurant的形容詞嗎,突然就覺得好餓了啊……”

作為一個合格的程序員,我一直把能夠將一項技術講給老婆聽,並且能給她講懂,作為我已經掌握了這項技術的標準。
如果我直接回答說,“REST就是Representational State Transfer的縮寫呀,翻譯為中文就是‘表述性狀態轉移’”,那她今晚肯定得罰我跪鍵盤。我必須找個合適的機會,把Restful的來龍去脈

給她形象的描述一遍。

“走,咱們去樓下咖啡廳吃個下午茶吧”,我對老婆說。

“一個芝士蛋糕,一杯拿鐵,兩條吸管,謝謝”,我對前臺的服務員說,然後我們找了個角落坐了下來。

Level 0 - 面向前臺

“剛才我們向前臺點了一杯拿鐵,這個過程可以用這段文字來描述”,說著,我在紙上寫下了這段JSON,雖然她不知道什麽叫JSON,但理解這段文字對於英語專業8級的她,實在再簡單不過。

{
    "addOrder": {
        "orderName": "latte"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5

“我們通過這段文字,告訴前臺,新增一筆訂單,訂單是一杯拿鐵咖啡”,接著,前臺給我們返回這麽一串回復:

{
    "orderId": "123456"
}
  • 1
  • 2
  • 3

“訂單ID?還是訂單編號?”
“恩恩,就是訂單編號”
“那我們就等著前臺喊‘訂單123456的客戶可以取餐了’,然後就可以開吃了!”
“哈哈,你真聰明,不過,在這之前,假設我們有一張會員卡,我們想查詢一下這張會員卡的余額,這時候,要向前臺發起另一個詢問”,我繼續在紙上寫著:

{
    "queryBalance": {
        "cardId": "886333"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5

“查詢卡號為886333的卡的余額?”
“真棒!接著,查詢的結果返回來了”

{
    "balance": "0"
}
  • 1
  • 2
  • 3

“切,沒錢……”
“哈哈,沒錢,現在我們要跟前臺說,這杯咖啡不要了”,我在紙上寫到:

{
    "deleteOrder": {
        "orderId": "123456"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5

“哼,這就把訂單取消啦?”

Level 1 - 面向資源

“現在這家咖啡店越做越大,來喝咖啡的人越來越多,單靠前臺顯然是不行的,店主決定進行分工,每個資源都有專人負責,我們可以直接面向資源操作。”
“面向資源?”
“是的,比如還是下單,請求的內容不變,但是我們多了一條消息”,我在紙上畫出這次的模型:

/orders

{
    "addOrder": {
        "orderName": "latte"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

“多了一個斜杠和orders?這是什麽意思?”
“這個表示我們這個請求是發給哪個資源的,訂單是一種資源,我們可以理解為是咖啡廳專門管理訂單的人,他可以幫我們處理所有有關訂單的操作,包括新增訂單、修改訂單、取消訂單等操作”
“Soga…”
“接著還是會返回訂單的編號給我們”

{
    "orderId": "123456"
}
  • 1
  • 2
  • 3

“下面,我們還是要查詢會員卡余額,這次請求的資源變成了cards”

/cards

{
    "queryBalance": {
        "cardId": "886333"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

“接下來是取消訂單”
“這個我會”,說著,她搶走我手上的筆,在紙上寫了起來:

/orders

{
    "deleteOrder": {
        "orderId": "123456"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Level2 - 打上標簽

“接下來,店主還想繼續優化他的咖啡廳的服務流程,他發現負責處理訂單的員工,每次都要去訂單內容裏面看是新增訂單還是刪除訂單,還是其他的什麽操作,十分不方便,於是規定,所有新增資源的請求,都在請求上面寫上大大的‘POST’,表示這是一筆新增資源的請求”

“其他種類的請求,比如查詢類的,用‘GET’表示,刪除類的,用‘DELETE’表示”

“還有修改類的,修改分為兩種,第一種,如果這個修改,無論發送多少次,最後一次修改後的資源,總是和第一次修改後的一樣,比如將拿鐵改為貓屎,那麽用‘PUT’表示;第二種,如果這個修改,每次修改都會讓這個資源和前一次的不一樣,比如是加一杯咖啡,那麽這種請求用‘PATCH’或者‘POST’表示”,一口氣講了這麽多,發現她有點似懂非懂。

“來,我們再來重復上面那個過程,來一杯拿鐵”,我邊說邊畫著:

POST /orders

{
    "orderName": "latte"
}
  • 1
  • 2
  • 3
  • 4
  • 5

“請求的內容簡潔多啦,不用告訴店員是addOrder,看到POST就知道是新增”,她聽的很認真,理解的也很透徹。
“恩恩,返回的內容還是一樣”

{
    "orderId": "123456"
}
  • 1
  • 2
  • 3

“接著是查詢會員卡余額,這次也簡化了很多”

GET /cards

{
    "cardId": "886333"
}
  • 1
  • 2
  • 3
  • 4
  • 5

“這個請求我們還可以進一步優化為這樣”

GET /cards/886333
  • 1

“Soga,直接把要查詢的卡號寫在後面了”
“沒錯,接著,取消訂單”

DELETE /orders/123456
  • 1

Level 3 - 完美服務

“忽然有一天,有個顧客抱怨說,他買了咖啡後,不知道要怎麽取消訂單,咖啡廳一個店員回了一句,你不會看我們的宣傳單嗎,上面不寫著:

DELETE /orders/{orderId}
  • 1

顧客反問道,誰會去看那個啊,店員不服,又說到,你瞎了啊你……據說後面兩人吵著吵著還打了起來…”
“噗,真是悲劇…”

“有了這次教訓,店長決定,顧客下了單之後,不僅給他們返回訂單的編號,還給顧客返回所有可以對這個訂單做的操作,比如告訴用戶如何刪除訂單。現在,我們還是發出請求,請求內容和上一次一樣”

POST /orders

{
    "orderName": "latte"
}
  • 1
  • 2
  • 3
  • 4
  • 5

“但是這次返回時多了些內容”

{
    "orderId": "123456",
    "link": {
        "rel": "cancel",
        "url": "/order/123456"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

“這次返回時多了一項link信息,裏面包含了一個rel屬性和url屬性,rel是relationship的意思,這裏的關系是cancel,url則告訴你如何執行這個cancel操作,接著你就可以這樣子來取消訂單啦”

DELETE /orders/123456
  • 1

“哈哈,這服務真是貼心,以後再也不用擔心店員和顧客打起來了”

“訂單123456的客戶可以取餐了”,伴隨著咖啡廳的廣播,我們吃起了下午茶,一杯拿鐵,兩支吸管……

對程序員的話

用了大白話,給老婆講明白了RESTful的來龍去脈,當然,我還是有些話想說的,只是怕老婆聽完一臉懵逼,沒給她說:

1、
上面講的Level0~Level3,來自Leonard Richardson提出的Richardson Maturity Model

技術分享

Level0和Level1最大的區別,就是Level1擁有了Restful的第一個特征——面向資源,這對構建可伸縮、分布式的架構是至關重要的。同時,如果把Level0的數據格式換成Xml,那麽其實就是SOAP,SOAP的特點是關註行為和處理,和面向資源的RESTful有很大的不同。
Level0和Level1,其實都很挫,他們都只是把HTTP當做一個傳輸的通道,沒有把HTTP當做一種傳輸協議

Level2,真正將HTTP作為了一種傳輸協議,最直觀的一點就是Level2使用了HTTP動詞,GET/PUT/POST/DELETE/PATCH….,這些都是HTTP的規範,規範的作用自然是重大的,用戶看到一個POST請求,就知道它不是冪等的,使用時要小心,看到PUT,就知道他是冪等的,調用多幾次都不會造成問題,當然,這些的前提都是API的設計者和開發者也遵循這一套規範,確保自己提供的PUT接口是冪等的。

Level3,關於這一層,有一個古怪的名詞,叫HATEOAS(Hypertext As The Engine Of Application State),中文翻譯為“將超媒體格式作為應用狀態的引擎”,核心思想就是每個資源都有它的狀態,不同狀態下,可對它進行的操作不一樣。理解了這一層,再來看看REST的全稱,Representational State Transfer,中文翻譯為“表述性狀態轉移”,是不是好理解多了?

Level3的Restful API,給使用者帶來了很大的遍歷,使用者只需要知道如何獲取資源的入口之後的每個URI都可以通過請求獲得,無法獲得就說明無法執行那個請求

現在絕大多數的RESTful接口都做到了Level2的層次,做到Level3的比較少。當然,這個模型並不是一種規範,只是用來理解Restful的工具。所以,做到了Level2,也就是面向資源和使用Http動詞,就已經很Restful了。Restful本身也不是一種規範,我比較傾向於用”風格“來形容它。如果你想深入了解Level3,可以閱讀《Rest in Practice》第五章。

2、
我跟老婆講的時候,用的數據格式是JSON,但是要強調一點,Restful對數據格式沒有限制,就算你用的是XML或者其他格式,只要符合上面提到的幾個特征,也算Restful。

3、
關於如何寫出好的Restful API,阮一峰老師已經寫過一篇非常棒的文章:RESTful API 設計指南,這篇文章將指導你寫出優雅的Restful。

如何給老婆解釋什麽是Restful【轉載】