對接口規範的一些思考

原由

團隊中若是不一樣的項目,不一樣的人員可能在接口設計上有許多不統一的地方。致使了開發效率低下的問題。
因爲我在工做中遇到了,因此整理下來,說一說本身的一些見解。javascript


怎樣進行接口規範化

由於每一個人對本身使用語言有不一樣的理解、HTTP協議熟悉程度不一樣、思惟邏輯、開發經驗不同。對接口規範有想法的人應該提出本身的觀點,給出本身的理由。讓別人去評價,討論出一套統一的規則,最終統一成一個內部的標準。
造成統一標準後由相關人員寫出示例。例如前端要對GET請求針對jQuery.ajaxfetchaxios等請求庫給出示例代碼。之後直接參照示例代碼進行開發。html

因爲每一個項目在定義接口時有許多不一樣的方式,我根據以往的經驗,從請求方法、請求頭、請求體、響應狀態碼、響應體等幾個方面對接口的規範說說本身的見解。前端

我對標準的理解

咱們不一樣的項目使用的請求方式大概有兩種:java

  • GET、POST
  • GET、POST、PUT、DELETE

若是使用前者,PSOT的URL中應該指明要執行的動做,然後者不須要指定。ios

POST /api/user/add HTTP/1.1
POST /api/user/set HTTP/1.1
POST /api/user/delete HTTP/1.1

# 這裏例子中約定PUT是新增,POST是修改
POST /api/user HTTP/1.1
PUT /api/user HTTP/1.1
DELETE /api/user HTTP/1.1

至於使用前者仍是後者,我更傾向於前者。
若是使用後者時,什麼狀況下使用PSOT、什麼狀況下使用PUT,搜索到了到了一些資料,但看不懂。git

接口URL

接口URL應該見名知意,有必定的規律。
這裏我不太懂,就不作過多贅述。github

數據類型的約定

前端請求中不該該有undefined,由於後端不支持(json也不支持)該數據類型。
若是Content-Typemultipart/form-data,前端不該該傳null,由於會被轉化成字符串,後端不能判斷出這是用戶輸入仍是null類型。ajax

每一個項目應該約定請求時下面這些數據表明什麼意思json

  • null數據類型表示什麼
  • 空字符串類型表示什麼

GET請求

做用

GET請求應該讀取數據,不該該產生任何的「反作用」操做。
這裏要注意一點瀏覽器對URL長度是有限制的,若是查詢的URL長度過長會引發不可預期的後果。能夠採用POST/PUT進行查詢。axios

方式

GET請求的參數應該放在請求的URL中而不該該放在請求體中。
例以下面是一個標準的這個GET請求(不相關HTTP頭字段已剔除)

GET /api/user?userId=12345 HTTP/1.1
Host: http://www.example.com

POST/PUT/DELETE請求

這三種請求方法傳參數格式都相同,下面以POST爲例。
POST類型使用的方式很是多樣,見識過各類各樣奇葩的方式,也是耽誤時間最長的,嚴重影響開發進度。這裏只討論我認爲標準的方式。

做用

POST請求用於新增、修改或刪除數據,少數狀況下用於查詢數據。

方式

POST請求的參數必須放在請求體中。
而POST的請求方式有四種方式

  • application/x-www-form-urlencoded
  • multipart/form-data
  • application/json
  • text/xml

這幾種方式經過HTTP頭中的Content-Type頭字段進行控制。

multipart/form-data

咱們如今使用的最多的是multipart/form-data

POST /api/user/set HTTP/1.1
Host: http://www.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2KbanAZwv0mKceX0

------WebKitFormBoundary2KbanAZwv0mKceX0
Content-Disposition: form-data; name="userName"

張三
------WebKitFormBoundary2KbanAZwv0mKceX0
Content-Disposition: form-data; name="userId"

123456
------WebKitFormBoundary2KbanAZwv0mKceX0--

這種方式不適合複雜數據類型的傳遞,例若有個接口須要同時修改多個用戶:

const userList = [
  {
    userID: 123,
    userName: '張三',
    isAdmin: true,
  }, {
    userID: 456,
    userName: '李四',
    isAdmin: false,
  },
];

那麼在POST請求時只能這麼作

POST /api/userlist/set HTTP/1.1
Host: http://www.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary2KbanAZwv0mKceX0

------WebKitFormBoundary2KbanAZwv0mKceX0
Content-Disposition: form-data; name="userID"

123,456
------WebKitFormBoundary2KbanAZwv0mKceX0
Content-Disposition: form-data; name="userName"

張三,李四
------WebKitFormBoundary2KbanAZwv0mKceX0
Content-Disposition: form-data; name="isAdmin"

1,0
------WebKitFormBoundary2KbanAZwv0mKceX0--

更重要的是這種方式不支持數據類型,傳入的全部格式的數據都會轉成字符串類型。後端常常要使用1表示true,須要將數組或對象拆分開。

application/json

這是我推薦使用的方式,有效的彌補了multipart/form-data的缺陷。
但不知什麼緣由如今咱們團隊基本不使用這種方式。
application/json也有一個缺陷就是不支持上傳文件(有特殊的方法這裏也不建議使用),想上傳文件仍是使用multipart/form-data

下面是請求示例

POST /user HTTP/1.1 
Host: http://www.example.com
Content-Type: application/json;charset=utf-8

[{"userID":123,"userName":"張三","isAdmin":true},{"userID":456,"userName":"李四","isAdmin":false}]

響應

不知道服務器對於不一樣的處理會返回什麼樣的狀態碼,這裏不作討論。
咱們會返回一個邏輯狀態碼code與提示信息msg,響應體像下面這樣。

{"code":200,"msg":"處理成功!","data":{}}

在此基礎上增長一些限制:

建議data字段始終爲對象類型

易於擴展,例如當前接口是用戶列表頁,data使用數組。v2版本接口加入了分頁查詢,就必須使data變爲對象類型了。

若是字段爲複雜類型,不容許爲null

複雜類型包括數組與對象。
爲了方便閱讀,這裏將json字符串轉化爲了JS對象。

const resBody = {
  code: 200,
  msg: '處理成功',
  data: {
    list: [
      {
        userID: 123,
        userName: '張三',
      },
    ],
  },
};

若是沒有數據的時候返回

const resBody = {
  code: 200,
  msg: '處理成功',
  data: {
    list: null,
  },
};

這樣前端在遍歷list時,null會致使代碼出錯,應該始終保證該字段的數據類型不變,正確返回方式以下。

const resBody = {
  code: 200,
  msg: '處理成功',
  data: {
    list: [],
  },
};

其餘

若是你有其餘補充或糾正,歡迎👏評論。
同時發表在GitHub

參考資料

相關文章
相關標籤/搜索