API設計要點

本文主要簡述API設計的要點。總體會偏向HTTP的接口,部分一樣適合非HTTP的接口。html

API版本管理

多版本兼容(控制維護的版本數,不宜過多)

HTTP GET:
https://haveibeenpwned.com/api/breachedaccount/foo
api-version: 2

spring中直接@RequestMapping(headers="api-version=2")便可以自動分發git

  • content-type acceptgithub

HTTP GET:
https://haveibeenpwned.com/api/breachedaccount/foo
Accept: application/vnd.haveibeenpwned.v2+json
  • content-type accept(版本單獨字段)web

HTTP GET:
https://haveibeenpwned.com/api/breachedaccount/foo
Accept: application/vnd.haveibeenpwned+json; version=2.0

如何下架舊版本(對過時版本的處理)

  • 對既有版本的訪問進行監控redis

  • 對要下架的版本隨機返回錯誤算法

API安全認證(兩方認證vs三方認證)

兩方認證,只涉及api服務提供方和使用方;spring

clipboard.png

三方認證,多了個用戶,一般是採用OAuth2來進行受權認證。json

clipboard.png

下面的這些僅僅涉及兩方認證(雙方認證的 api 一般的認證方式是使用一組 id 和密鑰,用 id 來標記應用,用密鑰來對請求作簽名):

  • 開啓https(web api的話)

  • Http Basic Authentication(通常內網使用配合https)
    在 Http header 中添加鍵值對 Authorization: Basic xxx (xxx 是 username:passowrd base64 值)。

  • 黑白名單(內網白,外網黑)

  • JWT (JSON Web Token)(適合移動端)
    JWT認證協議的格式爲Header.Payload.Signature。好比xxxxx.yyyyy.zzzzz。簽名內容是有Header+Payload+Secret經過HMAC SHA256算法加密而成。

clipboard.png
具體參考Introduction to JSON Web Tokens

API限流措施

HTTP/1.1 403 Forbidden
Date: Tue, 20 Aug 2013 14:50:41 GMT
Status: 403 Forbidden
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1377013266
{
"message": "API rate limit exceeded. \
See http://developer.github.com/v3/ \
#rate-limiting for details."
}

API的文檔化

業界的兩個方案,一個是Swagger使用Swagger快速打造REST API文檔,一個是最新的spring restdocs

API的接口設計

  • 錯誤碼處理
    建議充分利用http的錯誤碼,而後再細分,不建議本身再從新自定義一套。

    • 請求成功

      • 200 OK : 請求執行成功並返回相應數據,如 GET 成功

      • 201 Created : 對象建立成功並返回相應資源數據,如 POST 成功;建立完成後響應頭中應該攜帶頭標 Location ,指向新建資源的地址

      • 202 Accepted : 接受請求,但沒法當即完成建立行爲,好比其中涉及到一個須要花費若干小時才能完成的任務。返回的實體中應該包含當前狀態的信息,以及指向處理狀態監視器或狀態預測的指針,以便客戶端可以獲取最新狀態。

      • 204 No Content : 請求執行成功,不返回相應資源數據,如 PATCHDELETE 成功

    • 重定向
      重定向的新地址都須要在響應頭 Location 中返回

      • 301 Moved Permanently : 被請求的資源已永久移動到新位置

      • 302 Found : 請求的資源如今臨時從不一樣的 URI 響應請求

      • 303 See Other : 對應當前請求的響應能夠在另外一個 URI 上被找到,客戶端應該使用 GET 方法進行請求

      • 307 Temporary Redirect : 對應當前請求的響應能夠在另外一個 URI 上被找到,客戶端應該保持原有的請求方法進行請求

    • 條件請求

      • 304 Not Modified : 資源自從上次請求後沒有再次發生變化,主要使用場景在於實現數據緩存

      • 409 Conflict : 請求操做和資源的當前狀態存在衝突。主要使用場景在於實現併發控制

      • 412 Precondition Failed : 服務器在驗證在請求的頭字段中給出先決條件時,沒能知足其中的一個或多個。主要使用場景在於實現併發控制

    • 客戶端錯誤

      • 400 Bad Request : 請求體包含語法錯誤

      • 401 Unauthorized : 須要驗證用戶身份,若是服務器就算是身份驗證後也不容許客戶訪問資源,應該響應 403 Forbidden

      • 403 Forbidden : 服務器拒絕執行

      • 404 Not Found : 找不到目標資源

      • 405 Method Not Allowed : 不容許執行目標方法,響應中應該帶有 Allow 頭,內容爲對該資源有效的 HTTP 方法

      • 406 Not Acceptable : 服務器不支持客戶端請求的內容格式,但響應裏會包含服務端可以給出的格式的數據,並在 Content-Type 中聲明格式名稱

      • 410 Gone : 被請求的資源已被刪除,只有在肯定了這種狀況是永久性的時候纔可使用,不然建議使用 404 Not Found

      • 413 Payload Too Large : POST 或者 PUT 請求的消息實體過大

      • 415 Unsupported Media Type : 服務器不支持請求中提交的數據的格式

      • 422 Unprocessable Entity : 請求格式正確,可是因爲含有語義錯誤,沒法響應

      • 428 Precondition Required : 要求先決條件,若是想要請求能成功必須知足一些預設的條件

    • 服務端錯誤

      • 500 Internal Server Error : 服務器遇到了一個不曾預料的情況,致使了它沒法完成對請求的處理。

      • 501 Not Implemented : 服務器不支持當前請求所須要的某個功能。501405 的區別是:405 是表示服務端不容許客戶端這麼作,501 是表示客戶端或許能夠這麼作,但服務端尚未實現這個功能

      • 502 Bad Gateway : 做爲網關或者代理工做的服務器嘗試執行請求時,從上游服務器接收到無效的響應。

      • 503 Service Unavailable : 因爲臨時的服務器維護或者過載,服務器當前沒法處理請求。這個情況是臨時的,而且將在一段時間之後恢復。若是可以預計延遲時間,那麼響應中能夠包含一個 Retry-After 頭用以標明這個延遲時間(內容能夠爲數字,單位爲秒;或者是一個 HTTP 協議指定的時間格式)。若是沒有給出這個 Retry-After 信息,那麼客戶端應當以處理 500 響應的方式處理它。

    • 錯誤碼帶描述

503 Service Unavailable
{
"error_human": "The Database is currently unavailable.",
"error_code": "database_unavailable" (使用文字描述比起使用數字code會使開發者更容易懂)
}
  • 分頁

GET /employees?left=true&fields=name,joinDate&limit=10&offset=0&sortby=name&order=asc
{
    "data": {
        "total": 150,
        "employees": [
            {
                "name": "tom",
                "joinDate": "2015-10-01"
            },
            {
                "name": "jack",
                "joinDate": "2015-10-02"
            }
        ]
    }
}

或者採用page的方式同時加入links提示

?page=1&pre_page=10
{
    "data": {
        "total": 150,
        "links": [
            {
                "rel": "next",
                "href": "?page=2&per_page=10"
            },
            {
                "rel": "last",
                "href": "?page=11&per_page=10"
            }
        ],
        "employees": [
            {
                "name": "tom",
                "joinDate": "2015-10-01"
            },
            {
                "name": "jack",
                "joinDate": "2015-10-02"
            }
        ]
    }
}

或者

?limit=10: Reduce the number of results returned to the Consumer (for Pagination)
?offset=10: Send sets of information to the Consumer (for Pagination)
?limit=25&offset=50
  • 排序

?sortby=name&order=asc: Sort the results based on the specified attribute (ORDER BY name ASC)
  • 查詢字段選擇

GET http://api.example.org/user/12?fields=id,name,email (SELECT id, name, email FROM user WHERE user.id = 12)
  • 查詢過濾

?q=fluffy+fur(搜索)
?animal_type_id=1: Filter records which match the following condition (WHERE animal_type_id = 1)
  • 其餘

    • HATEOAS
      HATEOAS是Hypermedia as the Engine of Application State的縮寫形式,中文意思爲:超媒體應用狀態引擎。它的核心思想是使用超媒體表達應用狀態,與hypertext-driven思想是一致的。在此以前,咱們大多數的程序業務控制在前臺完成。例如:咱們會在前臺作註冊流程,咱們在前臺斷定下一步應該作什麼,能夠作什麼。當使用HATEOAS時,這些狀態流程控制都在應用程序的後臺完成。咱們使用超媒體來表達前臺作完某一步驟以後能夠作哪些? 這樣一來,前臺的任務就變得至關簡單了,前臺須要處理的是理解狀態表述,數據收集和結果顯示。

    • url組成

      • 網絡協議(HTTP, HTTPS)

      • 服務器地址

      • 版本

      • 接口名稱(用-代替_

      • ?參數列表(以後返回接口instagram是用_代替駝峯的

    • url命名限制

      • 不使用大寫字母

      • 使用中線-代替下劃線_,好比instagram的一個接口,https://api.instagram.com/v1/users/{user-id}/followed-by?access_token=ACCESS-TOKEN

      • 參數列表應該被encode過

    • 聚合資源必須經過父級資源操做
      示例: Profile是User的聚合資源,User有一個惟一且私有的Profile資源,只能經過User操做Profile。/users/123456/profiles

    • 組合資源要避免資源路徑嵌套
      示例: 一個系統裏面包含多個 applications,一個 application 又包含多個 users。那獲取 user 資源的路徑應該是怎樣的?

GET http://~/$version/systems/:systemId/applications/:applicationId/users/:userId

改成

GET http://~/$version/systems/:systemId
GET http://~/$version/applications/:applicationId
GET http://~/$version/users/:userId/

參考

相關文章
相關標籤/搜索