Restful API設計指南

這篇博文講先後端交互的Restful API設計考慮。API必定是基於HTTP協議並儘可能靠攏Restful規範設計的。若是不瞭解HTTP協議,能夠參考個人博文HTTP必知必會。關於Restful是怎麼回事,能夠考慮先參考阮一峯的博文理解RESTful架構;嫌麻煩的能夠略過直接閱讀個人這篇博文。html

基於資源的API設計

所謂資源,是一種對事物的抽象。一我的、一頭牛、一張電影票、一句話、一個想法均可以抽象爲資源。json

資源的URL表示

URL是資源的定位,是一種映射關係,即一個URL必定定位到最多不超過一個的資源。根據URL佈局的特色,分爲三種類型的資源:後端

  1. 集合資源api

    對於形如/users的資源稱爲集合資源,它表示一羣用戶。數組

  2. 個體資源服務器

    對於形如/users/u123的資源稱爲個體資源,它表示一個用戶,它是經過一個惟一標識的id(即u123)來肯定這個用戶。restful

  3. 子集合資源架構

    對於形如/users/u123/messages的資源稱爲子集合資源,它表示某個用戶的一羣消息,這個用戶是經過惟一標識的id(即u123)來肯定的。app

補充:關於id

資源的id對於同種類型的資源來講必定是惟一的。也就是說,肯定一個個體資源只須要經過下面的方式便可佈局

/messages/m123

而沒必要

/users/u123/messages/m123

資源的表述

資源自己是一種抽象,它必需要轉化爲一種機器可讀的形式才能進行傳輸和處理。表述方式的例子如表單形式、XML、JSON等。能夠經過HTTP頭Content-Type來指定資源的表述形式,常見的例子:

  • 純文本:text/plain
  • HTML文檔:text/html
  • 表單格式:application/x-www-form-urlencoded
  • XML文檔:text/xml
  • JSON文檔:application/json

這裏的設計中只考慮一種表述形式,即JSON。但願這一點不會給API的調用帶來困擾。

資源的操做

基本的增刪改查

對於的基本的增刪改查操做,除了定位到資源之外,只須要附加一個HTTP方法夠了。根據Restful規範,方法對於集合的意義通常是:

  1. POST:建立
  2. GET:查詢
  3. PUT:完整更新
  4. PATCH:部分更新
  5. DELETE:刪除

這些方法適用於不一樣的URL類型,總結以下:

  1. GET+(子)集合資源

    • GET /users 返回用戶集合
    • GET /users/u123/messages 返回指定用戶的消息集合
  2. POST+(子)集合資源

    • POST /users 建立一個新用戶
    • POST /users/u123/messages 爲指定用戶建立一個新消息
  3. GET+個體資源

    • GET /users/u123 返回指定用戶
  4. PUT/PATCH+個體資源

    • PUT /users/u123 更新指定用戶(完整)
    • PATCH /users/u123 更新指定用戶(部分)
  5. DELETE+個體資源

    • DELETE /users/u123 刪除指定用戶

其餘的動做

當對資源的操做跳出了基本的增刪改查範疇,就在資源的URL表示以後增長動做的名稱便可。這能夠經過兩個典型的例子來闡述。

例子一:用戶登陸

這個屬於對集合資源進行的操做。其接口表示可設定爲:

  • POST /users/login

只需在集合資源的URL表示(即/users)以後附加動做名(即/login)便可。在這種狀況下,POST是典型方法。

例子二:書籍標星和去標

這是一對接口,其中一個是對一本書進行標星操做,另一個是對其進行取消標星操做。這兩個接口都屬於對個體資源的操做。其接口表示可分別設定爲:

  • POST /books/b123/star
  • DELETE /books/b123/star

首先,須要在個體資源的URL表示(即/books/b123)以後附加動做名(即/star)。其次,這裏用到對立的兩個方法POST和DELETE。

例子三:查詢的count

一個查詢接口會返回一個資源數組,但有時咱們須要知道知足某個查詢條件的資源總數。這個在集合資源的URL以後附加動做count便可。例如:

  • GET /books/count 返回書籍資源總數
  • GET /users/count?age=18 返回年齡18歲的用戶資源總數

注意,這時分頁控制無效。

操做的參數

在參數設計裏,一個基本的設計原則是要保證簡潔,避免嵌套過深。參數的格式能夠根據實際狀況限定爲幾種或不限格式。不過,至少保證表單格式和JSON格式這兩種格式的支持。其中JSON格式支持任意的嵌套;表單格式對嵌套的支持不理想。

參數分爲通常參數控制參數。從形式上看,控制參數如下劃線開頭。這麼設計是爲了與通常參數進行區分。通常參數例如name、age等,控制參數例如_sort等。

通用參數總結

篩選

這裏的篩選只支持徹底匹配,適用於GET集合資源的接口。篩選的方式是簡單直接的,直接是字段名=值的形式便可。例以下面的接口返回年齡爲18的全部男性用戶:

GET /users?age=18&gender=male

排序(_sort)

排序參數_sort是逗號分隔的字段列表,以+/-表示升/降序。

  • age: age升序
  • +age: age升序,同上
  • -age: age降序
  • -age,name: 先以age降序,age相等的以name升序

分頁(_range)

分頁參數_range的構建也是直接的,如下劃線分隔它的起始和結束資源的序號。資源計數從1開始,這點要尤爲注意。

  • 10_100 : 返回第10個到第100個資源集合
  • _100 : 返回第1個到第100個集合資源
  • 1_ : 返回第1個到最後一個集合資源
  • _ : 返回全部的集合資源

內嵌(_embed)

說清楚內嵌的用法,先定義一個資源Book:

{
    id: 'b123',
    title: 'xxx',
    author: {
        id: 'u123',
        name: 'yyy'
    }
}

經過GET接口獲取的資源表述中,對於內嵌的資源默認只會返回其id,而不會返回其完整表述。例如調用GET /books/b123返回的數據是:

{
    id: 'b123',
    title: 'xxx',
    author: {
        id: 'u123'
    }
}

這個時候,想要獲取完整的author資源,須要再調用GET /users/u123

然而,經過_embed參數,能夠一步就直接返回包含完整User資源的author連接,就像咱們一開始定義的那樣。調用GET /users/u123?\_embed=author,返回如下的結果:

{
    id: 'b123',
    title: 'xxx',
    author: {
        id: 'u123',
        name: 'yyy'
    }
}

多個內嵌資源用逗號分隔便可。

操做的返回值

操做的返回內容,它的表述格式是可選的。只限定爲JSON格式是一種可選的簡潔方案。

基於操做類型的參數和返回值模式

不一樣的操做類型,其參數和返回值模式是有必定規律性的。現總結以下:

GET+(子)集合資源

這個操做請求的是一個資源集合,返回的是一個JSON數組。

其參數能包括:篩選、排序、分頁、內嵌。

GET+個體資源

這個操做請求的是一個個體資源,返回的是一個JSON對象。

其參數只包括:內嵌。

POST+(子)集合資源

這個操做請求建立一個新資源,返回的是一個JSON對象,表述新建立的資源。

其參數就是該資源的表述。

PUT/PATCH+個體資源

這個操做請求更新一箇舊資源,返回的是一個JSON對象,表述更新後的資源。

其參數就是該資源的表述。

DELETE+個體資源

這個操做請求刪除一個資源,無返回值,無參數。

其餘操做

其餘操做視狀況而定,通常無返回值,無參數。

操做的錯誤

任何操做都會發生出錯狀況。出錯的緣由有不少種,有源於客戶端的,也有源於服務器的。有預料中的,也有預料以外的。對於出錯狀況,服務器要向客戶端發送一個狀態碼及附加一個JSON格式的錯誤消息(這裏像返回值的考慮同樣也只考慮JSON格式了)。一個例子就是:

401 Unauthorized
{
    message: "沒登陸"
}

這裏的message字段做爲錯誤狀態的描述,做爲解釋出錯的緣由。若是表述的合適,能夠做爲最終用戶的提示信息,直接在彈框中顯示。

這裏面沒有考慮加入更多的字段了,好比一個code字段來更細緻的區別錯誤的類型。這種考慮是基於客戶端對於接口調用出錯無能爲力,通常能作的就兩種:

  1. 顯示錯誤信息;若是是冪等的接口,(可選地)重傳。
  2. 若是是受權相關錯誤,跳轉到登陸邏輯並可選地重傳。

補充

驗證信息

關於用戶的受權在HTTP和Restful中的方案,市面上有不少種。這裏介紹的是一種Token機制。很簡單,用戶經過某個接口(例如/users/login)獲取受權的Token,而後每次調用接口時將這個Token附加到Header Access-Token中。

_token僞id

用戶的Token不只用於受權,也用於標識用戶的身份。當須要傳遞用戶id的時候,每每發現用戶的id信息能夠從Token中獲取。舉個例子,id爲u123的用戶調用以下接口時:

GET /users/u123
Access-Token: 包含u123的受權信息

其中Token信息能夠從相應的Header中獲取,因此此時明確標明id u123沒有必要。此時能夠用一個佔位符()佔位一下便可。

GET /users/_token
Access-Token: 包含u123的受權信息
相關文章
相關標籤/搜索