restful API 規範(轉)

1. URI

URI 表示資源,資源通常對應服務器端領域模型中的實體類。html

URI規範

  1. 不用大寫;
  2. 用中槓-不用下槓_
  3. 參數列表要encode;
  4. URI中的名詞表示資源集合,使用複數形式。

資源集合 vs 單個資源

URI表示資源的兩種方式:資源集合、單個資源。git

資源集合:github

/zoos //全部動物園 /zoos/1/animals //id爲1的動物園中的全部動物

單個資源:數據庫

/zoos/1 //id爲1的動物園

避免層級過深的URI

/在url中表達層級,用於按實體關聯關係進行對象導航,通常根據id導航。json

過深的導航容易致使url膨脹,不易維護,如 GET /zoos/1/areas/3/animals/4(超過3層算過深),儘可能使用查詢參數代替路徑中的實體導航,如GET /animals?zoo=1&area=3api

對Composite資源的訪問

服務器端的組合實體必須在uri中經過父實體的id導航訪問。瀏覽器

組合實體不是first-class的實體,它的生命週期徹底依賴父實體,沒法獨立存在,在實現上一般是對數據庫表中某些列的抽象,不直接對應表,也無id。一個常見的例子是 User — Address,Address是對User表中zipCode/country/city三個字段的簡單抽象,沒法獨立於User存在。必須經過User索引到Address:GET /user/1/addresses緩存

Action不符合CRUD操做

利用RESTful原則像處理子資源同樣處理它。例如,Github的API讓你經過PUT /gists/:id/star 來 star a gist ,而經過DELETE /gists/:id/star來進行 unstar 。安全

咱們統一用post操做,在url的最後增長操做,以上面Github的例子來講,分別爲POST /gits/:id/star,POST /gits/:id/unstar服務器

 

2. Request

HTTP方法

經過標準HTTP方法對資源CRUD:

GET:查詢

GET /zoos GET /zoos/1 GET /zoos/1/employees

POST:建立單個資源。POST通常向「資源集合」型uri發起

POST /animals //新增動物 POST /zoos/1/employees //爲id爲1的動物園僱傭員工

PUT:更新單個資源(全量),客戶端提供完整的更新後的資源。與之對應的是 PATCH,PATCH 負責部分更新,客戶端提供要更新的那些字段。PUT/PATCH通常向「單個資源」型uri發起

PUT /animals/1 PUT /zoos/1

咱們用post和在url上加了「create」代替PUT,如:post: schools/create, post: schools/:id/update

DELETE:刪除

DELETE /zoos/1/employees/2 DELETE /zoos/1/employees/2;4;5 DELETE /zoos/1/animals //刪除id爲1的動物園內的全部動物

咱們用post和在url上加了「remove/delete」代替DELETE,  如: post:  schools/:id/remove

若是參數超過url長度限制,可使用post代替

安全性和冪等性

  1. 安全性:不會改變資源狀態,能夠理解爲只讀的;
  2. 冪等性:執行1次和執行N次,對資源狀態改變的效果是等價的。
 
GET
POST × ×
PUT ×
DELETE ×

安全性和冪等性均不保證反覆請求能拿到相同的response。以 DELETE 爲例,第一次DELETE返回200表示刪除成功,第二次返回404提示資源不存在,這是容許的。

冪等性參考:http://www.cnblogs.com/weidagang2046/archive/2011/06/04/2063696.html

複雜查詢

查詢能夠捎帶如下參數:

 
過濾條件 ?type=1&age=16 容許必定的uri冗餘,如/zoos/1/zoos?id=1
排序 ?sort=age,desc  
投影 ?whitelist=id,name,email  
分頁 ?pageSize=10&pageNum=3  
搜索 ?k=關鍵字1 k表示key,關鍵字

 

Bookmarker

常用的、複雜的查詢標籤化,下降維護成本。

如:

GET /trades?status=closed&sort=created,desc

快捷方式:

GET /trades#recently-closed 或者 GET /trades/recently-closed

Format

只用如下常見的3種body format:

  1. Content-Type: application/json

    POST /v1/animal HTTP/1.1
    Host: api.example.org
    Accept: application/json
    Content-Type: application/json
    Content-Length: 24
    
    {   
      "name": "Gir",
      "animalType": "12"
    }
  2. Content-Type: application/x-www-form-urlencoded (瀏覽器POST表單用的格式)

    POST /login HTTP/1.1
    Host: example.com
    Content-Length: 31
    Accept: text/html
    Content-Type: application/x-www-form-urlencoded
    
    "username":"root"
    "password":"Zion0101"(MD5加密)
  3. Content-Type: multipart/form-data; boundary=—-RANDOM_jDMUxq4Ot5 (表單有文件上傳時的格式)

Content Negotiation

資源能夠有多種表示方式,如json、xml、pdf、excel等等,客戶端能夠指定本身指望的格式,一般有兩種方式:

    1. http header Accept

      Accept:application/xml;q=0.6,application/atom+xml;q=1.0

      q爲各項格式的偏好程度

    2. url中加文件後綴:/zoo/1.json

6. Response

  1. 不要包裝: 
    response 的 body 直接就是數據,不要作多餘的包裝,示例:

    {
        "code":10000, "data":{"id":1,"name":"xiaotuan"} }

    失敗樣例:

    {
        "code":10103, "message":"" }
  2. 各HTTP方法成功處理後的數據格式:

     
  1. GET 單個對象、集合
    POST 新增成功的對象
    PUT/PATCH 更新成功的對象
    DELETE
  2. json格式的約定:

    1. 時間用長整形(毫秒數),客戶端本身按需解析(moment.js
    2. 不傳null字段

分頁response

{
       "code":10000
       "data":{
                   "pageNum": 3,
                   "pageSize": 10,
                   "totalCount": 100,
                   "totalPage": 10,
                   "items":[{},{},{}...]
       }

}

7. 錯誤處理

  1. 不要發生了錯誤但給2xx響應,客戶端可能會緩存成功的http請求;
  2. 正確設置http狀態碼,不要自定義;
  3. Response body 提供 1) 錯誤的代碼(日誌/問題追查);2) 錯誤的描述文本(展現給用戶)。

對第三點的實現稍微多說一點:

Java 服務器端通常用異常表示 RESTful API 的錯誤。API 可能拋出兩類異常:業務異常和非業務異常。業務異常由本身的業務代碼拋出,表示一個用例的前置條件不知足、業務規則衝突等,好比參數校驗不經過、權限校驗失敗。非業務類異常表示不在預期內的問題,一般由類庫、框架拋出,或因爲本身的代碼邏輯錯誤致使,好比數據庫鏈接失敗、空指針異常、除0錯誤等等。

業務類異常必須提供2種信息:

    1. 若是拋出該類異常,HTTP 響應狀態碼應該設成什麼;
    2. 異常的文本描述;

在Controller層使用統一的異常攔截器:

    1. 設置 HTTP 響應狀態碼;
    2. Response Body 的錯誤碼:對業務類異常,用自定義的其餘狀態碼;對非業務類異常,統一用10103
    3. Response Body 的錯誤描述:對業務類異常,用它指定的錯誤文本;對非業務類異常,線上能夠統一文案如「服務器端錯誤,請稍後再試」,開發或測試環境中用異常的 stacktrace,服務器端提供該行爲的開關。

經常使用的http狀態碼及使用場景(這裏咱們統一返回200,在消息體中使用自定義的狀態碼來處理):

 
400 bad request 經常使用在參數校驗
401 unauthorized 未經驗證的用戶,常見於未登陸。若是通過驗證後依然沒權限,應該 403(即 authentication 和 authorization 的區別)。
403 forbidden 無權限
404 not found 資源不存在
500 internal server error 非業務類異常
503 service unavaliable 由容器拋出,本身的代碼不要拋這個異常

 

8. 服務型資源

除了資源簡單的CRUD,服務器端常常還會提供其餘服務,這些服務沒法直接用上面提到的URI映射。如:

    1. 按關鍵字搜索;
    2. 計算地球上兩點間的距離;
    3. 批量向用戶推送消息

能夠把這些服務當作資源,計算的結果是資源的presentation,按服務屬性選擇合適的HTTP方法。

例:

GET /search?q=filter?category=file  搜索
GET /distance-calc?lats=47.480&lngs=-122.389&late=37.108&lnge=-122.448 POST /batch-publish-msg [{"from":0,"to":1,"text":"abc"},{},{}...]

9. 異步任務

對耗時的異步任務,服務器端接受客戶端傳遞的參數後,應返回建立成功的任務資源,其中包含了任務的執行狀態。客戶端能夠輪訓該任務得到最新的執行進度。

提交任務:
POST /batch-publish-msg
[{"from":0,"to":1,"text":"abc"},{},{}...] 返回: {"taskId":3,"createBy":"Anonymous","status":"running"} GET /task/3 {"taskId":3,"createBy":"Anonymous","status":"success"}

若是任務的執行狀態包括較多信息,能夠把「執行狀態」抽象成組合資源,客戶端查詢該狀態資源瞭解任務的執行狀況。

提交任務:
POST /batch-publish-msg
[{"from":0,"to":1,"text":"abc"},{},{}...] 返回: {"taskId":3,"createBy":"Anonymous"} GET /task/3/status {"progress":"50%","total":18,"success":8,"fail":1}

10. API的演進

版本

常見的三種方式:

    1. 在uri中放版本信息:GET /v1/users/1
    2. Accept Header:Accept: application/json+v1
    3. 自定義 Header:X-Api-Version: 1

用第一種,雖然沒有那麼優雅,但最明顯最方便。

URI失效

隨着系統發展,總有一些API失效或者遷移,對失效的API,返回404 not found 或 410 gone;對遷移的API,返回 301 重定向。

 

來源:http://novoland.github.io/%E8%AE%BE%E8%AE%A1/2015/08/17/Restful%20API%20%E7%9A%84%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83.html

參考內容:https://github.com/aisuhua/restful-api-design-references

相關文章
相關標籤/搜索