設計糟糕的 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!
作者:帝都羊,帝都一線民工。
宣告:本文為作者投稿,版權歸其個人所有。
熱 文 推 薦
☞ 剖析 AI 和大資料的分散式實踐 —— 2018 UCan下午茶·北京站
☞ 歷經外企、創業公司、大廠的程式設計師告訴你:第一份工作有多重要!
☞ 剛釋出!Python 一二線城市月薪 15K 起!12 月再奪語言榜首
☞ 一個程式設計師父親的呼籲:不要教你的孩子從小學程式設計!
☞ Python | 7招教你識別一個網站是否是Django後臺
print_r('點個贊吧!');
var_dump('點個贊吧!');
NSLog(@"點個贊吧!");
System.out.println("點個贊吧!");
console.log("點個贊吧!");
print("點個贊吧!");
printf("點個贊吧!\n");
cout << "點個贊吧!" << endl;
Console.WriteLine("點個贊吧!");
fmt.Println("點個贊吧!");
Response.Write("點個贊吧!");
alert("點個贊吧!")
echo "點個贊吧!"
點選“閱讀原文”,開啟 CSDN App 閱讀更貼心!