理解restful 架構 && RESTful API設計指南


  restful是前端和后端接口中都會使用的設計思想。

  網站即軟件,我們也常說的webapp,這種互聯網軟件采用的是“客戶端/服務器”模式,建立在分布式體系上。 網站開發,也可以完全采用軟件開發的模式,但是傳統上軟件和網絡還是不同的領域,因為: 軟件開發主要針對單機環境,而網絡是研究系統之間的通信。 互聯網的興起,使得這兩個領域開始融合,現在我們開始考慮,如何開發在互聯網環境中使用的軟件。

  • RESTful架構,就是目前最為流行的一種互聯網軟件架構,它結構清晰、符合標准、易於理解、擴展方便,所以正得到越來越多網站的采用。 

 

RESTful架構作者

  REST這個詞,是Fielding提出的。 他是HTTP協議(1.0和1.1)的主要設計者,Apache服務器軟件的設計者之一、Apache基金會的第一任主席。 

  REST作者fielding是這樣介紹的: REST是想在符合架構原理的前提下,理解和評估以網絡為基礎的應用軟件的架構設計,得到一個功能強、性能強、適宜通信的架構

 

 

RESTful名稱

 fielding將他對互聯網軟件的架構原則,定名為REST,即Representational State Transfer(表現層狀態轉化)的縮寫。 如果一個架構符合REST原則,就說是RESTful架構

 如果我們想要理解RESTful架構到底是怎樣的,我們就要去理解Representational State Transfer 這個詞, 只有每一個詞都知道是什么意思,才能更好的理解REST是一種怎樣的設計。

  

 

資源

  REST的名稱‘表現層狀態轉化’中,省略了主語,表現層實際上指的是‘資源’的表現層。

  所謂"資源",就是網絡上的一個實體,或者說是網絡上的一個具體信息。它可以是一段文本、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在你可以用一個URI(統一資源定位符)指向它,每種資源對應一個特定的URI。要獲取這個資源,訪問它的URI就可以,因此URI就成了每一個資源的地址或獨一無二的識別符

  所謂"上網",就是與互聯網上一系列的"資源"互動,調用它的URI。

 

 

表現層(Representation)

"資源"是一種信息實體,它可以有多種外在表現形式。我們把"資源"具體呈現出來的形式,叫做它的"表現層"(Representation)。

比如,文本可以用txt格式表現,也可以用HTML格式、XML格式、JSON格式表現,甚至可以采用二進制格式;圖片可以用JPG格式表現,也可以用PNG格式表現。

URI只代表資源的實體,不代表它的形式。嚴格地說,有些網址最后的".html"后綴名是不必要的,因為這個后綴名表示格式,屬於"表現層"范疇,而URI應該只代表"資源"的位置。它的具體表現形式,應該在HTTP請求的頭信息中用Accept和Content-Type字段指定,這兩個字段才是對"表現層"的描述。

 

 

狀態轉化(State Transfer)

  訪問一個網站,就代表了客戶端和服務器的一個互動過程。在這個過程中,勢必涉及到數據和狀態的變化。

  互聯網通信協議HTTP協議,是一個無狀態協議。這意味着,所有的狀態都保存在服務器端。因此,如果客戶端想要操作服務器,必須通過某種手段,讓服務器端發生"狀態轉化"(State Transfer)。而這種轉化是建立在表現層之上的,所以就是"表現層狀態轉化"。

  客戶端用到的手段,只能是HTTP協議。具體來說,就是HTTP協議里面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源。

 

綜述

  綜合上面的解釋,我們總結一下什么是RESTful架構:

  (1)每一個URI代表一種資源

  (2)客戶端和服務器之間,傳遞這種資源的某種表現層

  (3)客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀態轉化"。

 

RESTFUL設計誤區

  RESTful架構有一些典型的設計誤區。

  最常見的一種設計錯誤,就是URI包含動詞。因為"資源"表示一種實體,所以應該是名詞,URI不應該有動詞,動詞應該放在HTTP協議中。

  舉例來說,某個URI是/posts/show/1,其中show是動詞,這個URI就設計錯了,正確的寫法應該是/posts/1,然后用GET方法表示show。

  另一個設計誤區,就是在URI中加入版本號。 

  http://www.example.com/app/1.0/foo
  http://www.example.com/app/1.1/foo
  http://www.example.com/app/2.0/foo

  因為不同的版本,可以理解成同一種資源的不同表現形式,所以應該采用同一個URI。版本號可以在HTTP請求頭信息的Accept字段中進行區分。 

 

 

 

RESTful API

  網絡應用程序,分為前端和后端兩個部分。 當前的發展趨勢,就是前端設備層出不窮(手機、平板、桌面電腦、其他專用設備...)。

  因此,必須有一種統一的機制,方便不同的前端設備與后端進行通信。 這導致API構架的流行,甚至出現‘API First’的設計思想。 RESTful API是目前比較成熟的一套互聯網應用程序的API設計。 

 

協議

 API與用戶的通信協議,總是使用HTTPs協議。 

 

域名

 應該盡量將API部署在專用域名之下。

https://api.example.com

 我們經常可以看到類似的api作為開頭的域名。 

 如果api很簡單,我們可以放在主域名下面:

https://example.org/api/

 比如最常見的就是圖靈機器人的api接口:

http://www.tuling123.com/openapi/api?key=20ff1803ff65429b809a310653c9daac

 

版本

  應該講api的版本號放在url中。

https://api.example.com/v1/

  

另一種做法是將版本號放在http頭信息中,但是不如放在url中直觀方便。github采用這種方法。

 

 

路徑

  路徑又稱為‘終點’,表示api的具體網址。

  在RESTful架構中,每個網址代表一種資源(resource),所以網址中不能有動詞,只能有名詞,而且所用的名詞往往與數據庫的表格名對應。一般來說,數據庫中的表都是同種記錄的"集合"(collection),所以API中的名詞也應該使用復數。

  舉例來說,有一個API提供動物園(zoo)的信息,還包括各種動物和雇員的信息,則它的路徑應該設計成下面這樣。

  • https://api.example.com/v1/zoos
  • https://api.example.com/v1/animals
  • https://api.example.com/v1/employees

 

HTTP動詞

  對於資源的具體操作類型,由http動詞表示。

  常用的HTTP動詞有下面五個(括號里是對應的SQL命令)。  

GET(SELECT):從服務器取出資源(一項或多項)。
POST(CREATE):在服務器新建一個資源。
PUT(UPDATE):在服務器更新資源(客戶端提供改變后的完整資源)。
PATCH(UPDATE):在服務器更新資源(客戶端提供改變的屬性)。
DELETE(DELETE):從服務器刪除資源。

  還有兩個不常用的HTTP動詞。

  

  • HEAD:獲取資源的元數據。
  • OPTIONS:獲取信息,關於資源的哪些屬性是客戶端可以改變的。

 

  下面是一些例子。

GET /zoos:列出所有動物園
POST /zoos:新建一個動物園
GET /zoos/ID:獲取某個指定動物園的信息
PUT /zoos/ID:更新某個指定動物園的信息(提供該動物園的全部信息)
PATCH /zoos/ID:更新某個指定動物園的信息(提供該動物園的部分信息)
DELETE /zoos/ID:刪除某個動物園
GET /zoos/ID/animals:列出某個指定動物園的所有動物
DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物

 

  

過濾信息

  如果記錄數量很多,服務器不可能都將它們返回給用戶。API應該提供參數,過濾返回結果。

  下面是一些常見的參數。

?limit=10:指定返回記錄的數量
?offset=10:指定返回記錄的開始位置。
?page=2&per_page=100:指定第幾頁,以及每頁的記錄數。
?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。
?animal_type_id=1:指定篩選條件

  實際上這些也就是get請求中我們傳遞的參數了,包括limit限制條數,offset限制開始位置等等都是我們常用的一些請求參數用於過濾。

 

 

狀態碼

 服務器向用戶返回的狀態碼和提示信息,常見的有以下一些(方括號中是該狀態碼對應的HTTP動詞)。即狀態碼是后台根據情況寫好發送給前端的,400、200、404等等都是如此。 狀態碼還是需要正確書寫的,這樣有利於前端准確判斷出現的問題是屬於前端還是后端。

200 OK - [GET]:服務器成功返回用戶請求的數據,該操作是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
202 Accepted - [*]:表示一個請求已經進入后台排隊(異步任務)
204 NO CONTENT - [DELETE]:用戶刪除數據成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操作,該操作是冪等的。
401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。
403 Forbidden - [*] 表示用戶得到授權(與401錯誤相對),但是訪問是被禁止的。
404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操作,該操作是冪等的。
406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 當創建一個對象時,發生一個驗證錯誤。
500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將無法判斷發出的請求是否成功。

 

 

 

錯誤處理

  如果狀態碼是4xx,就應該向用戶返回出錯信息。一般來說,返回的信息中將error作為鍵名,出錯信息作為鍵值即可。如下:

{ error: "Invalid API key" }

 

 

返回結果

針對不同的操作,服務器向用戶返回的結果符合下面規范。

GET /collection:返回資源對象的列表(數組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔

 

 

 

Hypermedia API

  RESTful API最好做到Hypermedia,即返回結果中提供鏈接,連向其他API方法,使得用戶不查文檔,也知道下一步應該做什么。

  比如,當用戶向api.example.com的根目錄發出請求,會得到這樣一個文檔。

  

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

 

上面代碼表示,文檔中有一個link屬性,用戶讀取這個屬性就知道下一步該調用什么API了。rel表示這個API與當前網址的關系(collection關系,並給出該collection的網址),href表示API的路徑,title表示API的標題,type表示返回類型。

Hypermedia API的設計被稱為HATEOAS。Github的API就是這種設計,訪問api.github.com會得到一個所有可用API的網址列表。

{ "current_user_url": "https://api.github.com/user", "authorizations_url": "https://api.github.com/authorizations",  // ... }

從上面可以看到,如果想獲取當前用戶的信息,應該去訪問api.github.com/user,然后就得到了下面結果。


{ "message": "Requires authentication", "documentation_url": "https://developer.github.com/v3" } 

上面代碼表示,服務器給出了提示信息,以及文檔的網址。

 

 

https://api.github.com/

 

 

 

 

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM