1. 程式人生 > >RESTful規範Api最佳設計實踐

RESTful規範Api最佳設計實踐

RESTful是目前比較流行的介面路徑設計規範,基於HTTP,一般使用JSON方式定義,通過不同HttpMethod來定義對應介面的資源動作,如:新增(POST)、刪除(DELETE)、更新(PUT、PATCH)、查詢(GET)等。

路徑設計

RESTful設計規範內,每一個介面被認為是一個資源請求,下面我們針對每一種資源型別來看下API路徑設計。

路徑設計注意事項如下所示:

  • 資源名使用複數
  • 資源名使用名詞
  • 路徑內不帶特殊字元
  • 避免多級URL

新增資源

請求方式 示例路徑
POST https://api.yuqiyu.com/v1/users

新增資源使用POST方式來定義介面,新增資源資料通過RequestBody

方式進行傳遞,如下所示:

curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
    "name": "恆宇少年", 
    "age": 25, 
    "address": "山東濟南"
}'

新增資源後接口應該返回該資源的唯一標識,比如:主鍵值。

{
  "id" : 1,
  "name" : "恆宇少年"
}

通過返回的唯一標識來操作該資源的其他資料介面。

刪除資源

請求方式 示例路徑 備註
DELETE https://api.yuqiyu.com/v1/users 批量刪除資源
DELETE https://api.yuqiyu.com/v1/users/{id} 刪除單個資源

刪除資源使用DELETE方式來定義介面。

  • 根據主鍵值刪除單個資源

    curl -X DELETE https://api.yuqiyu.com/v1/users/1
    

    將資源的主鍵值通過路徑的方式傳遞給介面。

  • 刪除多個資源

    curl -X DELETE -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
        "userIds": [
            1, 
            2, 
            3
        ]
    }'
    

    刪除多個資源時通過RequestBody方式進行傳遞刪除條件的資料列表,上面示例中通過資源的主鍵值集合作為刪除條件,當然也可以通過資源的其他元素作為刪除的條件,比如:name

更新資源

請求方式 示例路徑 備註
PUT https://api.yuqiyu.com/v1/users/{id} 更新單個資源的全部元素
PATCH https://api.yuqiyu.com/v1/users/{id} 更新單個資源的部分元素

在更新資源資料時使用PUT方式比較多,也是比較常見的,如下所示:

curl -X PUT -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users/1 -d '{
    "name": "恆宇少年", 
    "age": 25, 
    "address": "山東濟南"
}'

查詢單個資源

請求方式 示例路徑 備註
GET https://api.yuqiyu.com/v1/users/{id} 查詢單個資源
GET https://api.yuqiyu.com/v1/users?name={name} 非唯一標識查詢資源
  • 唯一標識查詢單個資源

    curl https://api.yuqiyu.com/v1/users/1
    

    通過唯一標識查詢資源時,使用路徑方式傳遞標識值,體現出層級關係。

  • 非唯一標識查詢單個資源

    curl https://api.yuqiyu.com/v1/users?name=恆宇少年
    

    查詢資源資料時不僅僅都是通過唯一標識值作為查詢條件,也可能會使用資源物件內的某一個元素作為查詢條件。

分頁查詢資源

請求方式 示例路徑
GET https://api.yuqiyu.com/v1/users?page=1&size=20

分頁查詢資源時,我們一般需要傳遞兩個引數作為分頁的條件,page代表了當前分頁的頁碼,size則代表了每頁查詢的資源數量。

curl https://api.yuqiyu.com/v1/users?page=1&size=20

如果分頁時需要傳遞查詢條件,可以繼續追加請求引數。

https://api.yuqiyu.com/v1/users?page=1&size=20&name=恆宇少年

動作資源

有時我們需要有動作性的修改某一個資源的元素內容,比如:重置密碼。

請求方式 示例路徑 備註
POST https://api.yuqiyu.com/v1/users/{id}/actions/forget-password -

使用者的唯一標識在請求路徑中進行傳遞,而修改後的密碼通過RequestBody方式進行傳遞,如下所示:

curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users/1/actions/forget-password -d '{
    "newPassword": "123456"
}'

版本號

版本號是用於區分Api介面的新老標準,比較流行的分別是介面路徑頭資訊這兩種方式傳遞。

  • 介面路徑方式

    我們在部署介面時約定不同版本的請求使用HTTP代理轉發到對應版本的介面閘道器,常用的請求轉發代理比如使用:Nginx等。

    這種方式存在一個弊端,如果多個版本同時將請求轉發到同一個閘道器時,會導致具體版本的請求轉發失敗,我們訪問v1時可能會轉發到v2,這並不是我們期望的結果,當然可以在閘道器新增一層攔截器,通過提取路徑上班的版本號來進行控制轉發。

    # v1版本的請求
    curl https://api.yuqiyu.com/v1/users/1
    # v2版本的請求
    curl https://api.yuqiyu.com/v2/users/1
    
  • 頭資訊方式

    我們可以將訪問的介面版本通過HttpHeader的方式進行傳遞,在閘道器根據提取到的頭資訊進行控制轉發到對應版本的服務,這種方式資源路徑的展現形式不會因為版本的不同而變化

    # v1版本的請求
    curl -H 'Accept-Version:v1' https://api.yuqiyu.com/users/1
    # v2版本的請求
    curl -H 'Access-Version: v2' https://api.yuqiyu.com/users/1
    

    這兩個版本的請求可能請求引數、返回值都不一樣,但是請求的路徑是一樣的。

    版本頭資訊的Key可以根據自身情況進行定義,推薦使用Accpet形式,詳見<a href="http://www.informit.com/articles/article.aspx?p=1566460" target="_blank">Versioning REST Services</a>。

狀態碼

RESTful設計規範內我們需要充分的裡面HttpStatus請求的狀態碼來判斷一個請求傳送狀態,本次請求是否有效,常見的HttpStatus狀態碼如下所示:

狀態碼 發生場景
200 請求成功
201 新資源建立成功
204 沒有任何內容返回
400 傳遞的引數格式不正確
401 沒有許可權訪問
403 資源受保護
404 訪問的路徑不正確
405 訪問方式不正確,GET請求使用POST方式訪問
410 地址已經被轉移,不可用
415 要求介面返回的格式不正確,比如:客戶端需要JSON格式,介面返回的是XML
429 客戶端請求次數超過限額
500 訪問的接口出現系統異常
503 服務不可用,服務一般處於維護狀態。

針對不同的狀態碼我們要做出不同的反饋,下面我們先來看一個常見的引數異常錯誤響應設計方式:

# 發起請求
curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
    "name": "", 
    "age": 25, 
    "address": "山東濟南"
}'
# 響應狀態
HttpStatus 200
# 響應內容
{
    "code": "400", 
    "message": "使用者名稱必填."
}

在服務端我們可以控制不同狀態碼、不同異常的固定返回格式,不應該將所有的異常請求都返回200,然後對應返回錯誤,正確的方式:

# 發起請求
curl -X POST -H 'Content-Type: application/json' https://api.yuqiyu.com/v1/users -d '{
    "name": "", 
    "age": 25, 
    "address": "山東濟南"
}'
# 響應狀態
HttpStatus 400
# 響應內容
{
    "error": "Bad Request", 
    "message": "使用者名稱必填."
}

響應格式

介面的響應格式應該統一

每一個請求成功的介面返回值外層格式應該統一,在服務端可以採用實體方式進行泛型返回。

如下所示:

/**
 * Api統一響應實體
 * {@link #data } 每個不同的介面響應的資料內容
 * {@link #code } 業務異常響應狀態碼
 * {@link #errorMsg} 業務異常訊息內容
 * {@link #timestamp} 介面響應的時間戳
 *
 * @author 恆宇少年 - 於起宇
 */
@Data
public class ApiResponse<T> implements Serializable {
    private T data;
    private String code;
    private String errorMsg;
    private Long timestamp;
}
  • data

    由於每一個API的響應資料型別不一致,所以在上面採用的泛型的泛型進行返回,data可以返回任意型別的資料。

  • code

    業務邏輯異常碼,比如:USER_NOT_FOUND(使用者不存在)這是介面的約定

  • errorMsg

    對應code值得描述。

  • timestamp

    請求響應的時間戳

總結

RESTfulAPI的設計規範,並不是所有的介面都應該遵循這一套規範來設計,不過我們在設計初期更應該規範性,這樣我們在後期閱讀程式碼時根據路徑以及請求方式就可以瞭解介面的主