1. 程式人生 > >Restful API設計規範

Restful API設計規範

理解RESTful架構

Restful API設計指南

 

 

理解RESTful架構

越來越多的人開始意識到,網站即軟體,而且是一種新型的軟體。

這種"網際網路軟體"採用客戶端/伺服器模式,建立在分散式體系上,通過網際網路通訊,具有高延時(high latency)、高併發等特點。

網站開發,完全可以採用軟體開發的模式。但是傳統上,軟體和網路是兩個不同的領域,很少有交集;軟體開發主要針對單機環境,網路則主要研究系統之間的通訊。網際網路的興起,使得這兩個領域開始融合,現在我們必須考慮,如何開發在網際網路環境中使用的軟體。

 

RESTful架構,就是目前最流行的一種網際網路軟體架構。它結構清晰、符合標準、易於理解、擴充套件方便,所以正得到越來越多網站的採用。

但是,到底什麼是RESTful架構,並不是一個容易說清楚的問題。下面,我就談談我理解的RESTful架構。

一、起源

REST這個詞,是Roy Thomas Fielding在他2000年的博士論文中提出的。

Fielding是一個非常重要的人,他是HTTP協議(1.0版和1.1版)的主要設計者、Apache伺服器軟體的作者之一、Apache基金會的第一任主席。所以,他的這篇論文一經發表,就引起了關注,並且立即對網際網路開發產生了深遠的影響。

他這樣介紹論文的寫作目的:

"本文研究電腦科學兩大前沿----軟體和網路----的交叉點。長期以來,軟體研究主要關注軟體設計的分類、設計方法的演化,很少客觀地評估不同的設計選擇對系統行為的影響。而相反地,網路研究主要關注系統之間通訊行為的細節、如何改進特定通訊機制的表現,常常忽視了一個事實,那就是改變應用程式的互動風格比改變互動協議,對整體表現有更大的影響。我這篇文章的寫作目的,就是想在符合架構原理的前提下,理解和評估以網路為基礎的應用軟體的架構設計,得到一個功能強、效能好、適宜通訊的架構。"

(This dissertation explores a junction on the frontiers of two research disciplines in computer science: software and networking. Software research has long been concerned with the categorization of software designs and the development of design methodologies, but has rarely been able to objectively evaluate the impact of various design choices on system behavior. Networking research, in contrast, is focused on the details of generic communication behavior between systems and improving the performance of particular communication techniques, often ignoring the fact that changing the interaction style of an application can have more impact on performance than the communication protocols used for that interaction. My work is motivated by the desire to understand and evaluate the architectural design of network-based application software through principled use of architectural constraints, thereby obtaining the functional, performance, and social properties desired of an architecture. )

 

二、名稱

Fielding將他對網際網路軟體的架構原則,定名為REST,即Representational State Transfer的縮寫。我對這個片語的翻譯是"表現層狀態轉化"。

如果一個架構符合REST原則,就稱它為RESTful架構。

要理解RESTful架構,最好的方法就是去理解Representational State Transfer這個片語到底是什麼意思,它的每一個詞代表了什麼涵義。如果你把這個名稱搞懂了,也就不難體會REST是一種什麼樣的設計。

三、資源(Resources)

REST的名稱"表現層狀態轉化"中,省略了主語。"表現層"其實指的是"資源"(Resources)的"表現層"。

所謂"資源",就是網路上的一個實體,或者說是網路上的一個具體資訊。它可以是一段文字、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在。你可以用一個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架構有一些典型的設計誤區。

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

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

如果某些動作是HTTP動詞表示不了的,你就應該把動作做成一種資源。比如網上匯款,從賬戶1向賬戶2匯款500元,錯誤的URI是:

 

1 POST  /accounts/1/transfer/500/to/2

正確的寫法是把動詞transfer改成名詞transaction,資源不能是動詞,但是可以是一種服務:

1 2 3 4 POST  /transaction  HTTP /1 .1 Host: 127.0.0.1   from=1&to=2&amount=500.00

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

1 2 3 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欄位中進行區分(參見Versioning REST Services):

1 2 3 Accept: vnd.example-com.foo+json; version=1.0 Accept: vnd.example-com.foo+json; version=1.1 Accept: vnd.example-com.foo+json; version=2.0

*注,雖說restfull規範建議版本號放在請求頭而不是url裡,但事實上為了使用方便,大多數開發者還是喜歡把版本號放在url上,這樣容易直觀區分

  

Restful API設計指南

接下來我將介紹RESTful API的設計細節,探討如何設計一套合理、好用的API

一、協議

API與使用者的通訊協議,總是使用HTTPs協議

二、域名

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

1 https: //api .example.com

如果確定API很簡單,不會有進一步擴充套件,可以考慮放在主域名下。  

1 https: //example .org /api/

三、版本(Versioning)

應該將API的版本號放入URL。

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

另一種做法是,將版本號放在HTTP頭資訊中,但不如放入URL方便和直觀。Github採用這種做法。

四、路徑(Endpoint)

路徑又稱"終點"(endpoint),表示API的具體網址。

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

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

1 2 3 https: //api .example.com /v1/zoos https: //api .example.com /v1/animals https: //api .example.com /v1/employees

五、HTTP動詞

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

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

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

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

1 2 HEAD:獲取資源的元資料。 OPTIONS:獲取資訊,關於資源的哪些屬性是客戶端可以改變的。

下面是一些例子。

1 2 3 4 5 6 7 8 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 :刪除某個指定動物園的指定動物

六、過濾資訊(Filtering)

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

下面是一些常見的引數。

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

引數的設計允許存在冗餘,即允許API路徑和URL引數偶爾有重複。比如,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。

七、狀態碼(Status Codes)

伺服器向用戶返回的狀態碼和提示資訊,常見的有以下一些(方括號中是該狀態碼對應的HTTP動詞)。

1 2 3 4 5 6 7 8 9 10 11 12 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 - [*]:伺服器發生錯誤,使用者將無法判斷髮出的請求是否成功。

狀態碼的完全列表參見這裡

八、錯誤處理(Error handling)

如果狀態碼是4xx,就應該向使用者返回出錯資訊。一般來說,返回的資訊中將error作為鍵名,出錯資訊作為鍵值即可。

1 2 3 {      error:  "Invalid API key" }

九、返回結果

針對不同操作,伺服器向用戶返回的結果應該符合以下規範。

1 2 3 4 5 6 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的根目錄發出請求,會得到這樣一個文件。

1 2 3 4 5 6 { "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的網址列表。

1 2 3 4 5 {    "current_user_url" "https://api.github.com/user" ,    "authorizations_url" "https://api.github.com/authorizations" ,    / /  ... }

從上面可以看到,如果想獲取當前使用者的資訊,應該去訪問api.github.com/user,然後就得到了下面結果。

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

上面程式碼表示,伺服器給出了提示資訊,以及文件的網址。  

十一、其他

(1)API的身份認證應該使用OAuth 2.0框架。

(2)伺服器返回的資料格式,應該儘量使用JSON,避免使用XML。

  

  

十二、Django rest framework最佳實踐

http://www.cnblogs.com/alex3714/articles/7131523.html   

  

  

本文轉載自 http://www.ruanyifeng.com/blog/2014/05/restful_api.html