1. 程式人生 > >設計糟糕的 RESTful API 就是在浪費時間

設計糟糕的 RESTful API 就是在浪費時間

現在微服務真是火的一塌糊塗。大街小巷,逢人必談微服務,各路大神紛紛忙著把自家的單體服務拆解成多個Web微小服務。而作為微服務之間通訊的橋樑,Web API的設計就顯得非常重要。

HTTP是目前網際網路使用最多的協議,但是作為HTTP協議創始人之一的Roy Fielding認為,過去十年,大家都在錯誤地使用HTTP協議。刪除一個數據,路徑往往是 delete/{id},更新一條資料,路徑往往被定義為update/{id}。你已經被Roy在心裡默默的鄙視了!

Roy Fielding提出了一種用於設計Web服務的架構方法,稱為Representational State Transfer(REST)。REST的概念是將API結構分離為操作和資源,使用HTTP方法GET、DELETE、POST和PUT操作資源。

設計糟糕的REST API = 浪費時間!優秀的API就像一位藝術家在舞臺上表演,其使用者就是觀眾,能給所有人帶來賞心悅目的美感。

REST API裡面的術語

Resource(資源)是指代表某種東西的物件,它具有一些與之相關的資料,並且可以有一組方法對其進行操作。例如,學校、班級和學生是資源,刪除、新增、更新是要對這些資源執行的操作。

Collections(集合)是一組資源,例如,211大學是全國211所優質大學的集合。

URL(統一資源定位符)是可以通過其定位資源的路徑,並且可以對其執行某些操作。

API設計使用名詞,而不是動詞

獲取所有學生,可能通過如下API:/getAllStudents;

增加學生:/addNewStudent;

更新學生:/updateStudent;

刪除學生:/deleteStudent;

刪除所有學生:/deleteStudents;

獲取三好學生:/getSanHaoStudents;

......

對於不同的操作,會衍生出越來越多的API介面,數量不停的增多,介面將會變得混亂和難以維護。

有沒有感覺哪裡不對?

URL應僅包含資源(名詞)而不包含動作或者動詞,增加學生的API路徑:/addNewStudent,包含操作addNew以及資源名稱Student。

那麼正確的方法是什麼?

/schools 是一個很好的例子,不包含任何動作。但是我們怎麼告訴伺服器,有關學校資源的操作呢?例如增加,刪除或者更新學校?

這就是HTTP方法(GET,POST,DELETE,PUT)(也成為動詞)發揮作用的地方。API介面的資源應始終為複數,如果我們要訪問資源的一個例項,我們可以在URL中傳遞id或者name之類的。

GET 路徑 /schools 獲取所有的學校;

GET 路徑 /schools/清華 獲取名字叫清華大學的詳細資訊;

DELETE 路徑 /schools/清華 從學校列表中,刪除清華大學。

資源和資源之間也有可能有父子關係,那又應該如何設計?例如學校的學生,下面是一些示例:

GET /schools/清華/students 獲取清華大學的所有學生;

GET /schools/清華/students/張三 獲取清華大學名字叫張三的學生的詳細資訊;

DELETE /schools/清華/students/張三 刪除清華大學名字叫張三的學生。

合理利用HTTP本身的方法

HTTP已定義了幾組方法,這些方法指示要對資源執行什麼型別的操作。我們制定Web介面,要合理利用HTTP的方法。

URL是說白了,就是一個句子,其中資源是名詞,HTTP方法是動詞。

  • GET 方法從資源請求資料,不應產生任何其他作用。例如/schools/清華/students,返回所有清華大學的學生。
  • POST方法請求伺服器在資料庫中建立資源,主要是在提交Web表單時。/schools/清華/students/張三,在清華大學的學生資源,新增一個張三的學生。POST是非冪等的,這意味著多個請求將具有不同的效果。
  • PUT方法請求伺服器更新資源或建立資源(如果不存在)。/schools/清華/students/張三, 對清華大學下的學生資源中,更新或者建立張三。PUT是冪等的,這意味著多個請求將具有相同的效果。
  • DELETE方法請求從資料庫中刪除資源或其例項。/schools/清華/students/張三,從清華大學的學生集合中,刪除學生張三的資源。

使用JSON作為通訊格式

JSON閱讀性更高,擴充套件性更強,適合各種環境和語言進行解析,現在大的網際網路公司,對外提供的API基本都使用JSON。

使用HTTP狀態碼

當客戶端通過API向伺服器發出請求時,客戶端應該知道反饋,無論是失敗、成功還是請求錯誤。 HTTP狀態程式碼是一系列標準化程式碼,針對HTTP請求的可能會發生的各種情況,而伺服器應始終返回正確的狀態程式碼。很多人喜歡把錯誤資訊放在返回值中,典型的Code和Message,其實是不合理的。

下面是HTTP狀態碼,可以合理利用處理各種請求反饋,將HTTP自身的錯誤和伺服器內部的錯誤,有一個很好的區分:

2xx(成功類別)

200 Ok表示GET,PUT或POST成功的標準HTTP響應。

201 Created每當建立新例項時,都應返回此狀態程式碼。例如,使用POST方法建立新例項時,應始返回201狀態程式碼。

204 No Content表示請求已成功處理,但未返回任何內容。

3xx(重定向類別)

304 Not Modified表示客戶端已在其快取中有響應,因此無需再次傳輸相同的資料。

4xx(客戶端錯誤類別)

這些狀態程式碼表示客戶端已提出錯誤請求。

400 Bad Request表示未處理客戶端的請求,因為伺服器無法理解客戶端要求的內容。

401 Unauthorized表示不允許客戶端訪問資源,並應使用所需憑據重新請求。

403 Forbidden表示請求有效且客戶端已通過身份驗證,但不允許客戶端出於任何原因訪問該頁面或資源。例如,有時不允許授權客戶端訪問伺服器上的目錄。

404 Not Found表示請求的資源現在不可用。

410 Gone表示已移動的請求資源不再可用。

5xx(伺服器錯誤類別)

500內部伺服器錯誤表示請求有效,但伺服器完全混淆,並要求伺服器提供某些意外情況。

503 Service Unavailable大多數情況下表示伺服器已關閉或無法接收和處理請求,例如伺服器正在進行維護。

搜尋、排序、過濾和分頁

所有這些操作都只是對一個數據集的查詢,將不會有新的API集來處理這些操作,我們需要使用GET方法API附加查詢引數。

下面看幾個例子:

GET /schools ? search = 清華大學 在大學集合中,搜尋清華大學;

GET /schools ? sort = rank_asc 按照升序排列學校;

GET /schools ? location = 北京 按照城市對學校過濾;

GET /schools ? page=6 獲取第六頁的學校列表。

使用版本控制

例如下面兩個版本地址:

http://api.yourservice.com/v1/schools/清華

http://api.yourservice.com/v2/schools/清華

在API上加入版本資訊可以有效的使使用者訪問正確的API,v2是新開發功能,開發階段讓所有使用者訪問v1,等開發完成統一切到v2。這樣可以有效地跨版本訪問,例如在v2版本,還需要訪問v1版本的一些介面。

總結

最後總結一下:

  • API介面都用小寫;
  • 使用JSON通訊;
  • API帶版本控制,比如v1、v2;
  • 使用Token令牌進行鑑權;
  • 路徑中單詞連線使用中劃線-;
  • 使用HTTP自身的方法表示增刪改查資源, GET:查詢,POST:新增,PUT:更新,DELETE:刪除;
  • 合理使用HTTP狀態碼,200,201,400,401,403,500。比如401表示使用者身份認證失敗,403表示驗證身份通過了,但是無許可權操作資源。

在此,祝大家都設計出優秀的Restful API!