前后端接口規(guī)范

背景與目標

1.背景:由于后續(xù)前后端項目重構(gòu),改動量較大,接口統(tǒng)一使用Java,規(guī)定好前后端協(xié)議規(guī)范,易于開發(fā)后期維護。
2.本規(guī)范的目標:簡潔、統(tǒng)一開放。

注意本規(guī)范是前端組內(nèi)部制定的接口規(guī)范模板,在制定接口規(guī)范時候參考,在落地時可根據(jù)實際情況作出調(diào)整,文檔進行同時進行更新調(diào)整,后續(xù)前后端就按照這個規(guī)范執(zhí)行。

規(guī)范內(nèi)容

1. 基礎(chǔ)約定

1.1 接口路徑以 /api/[version]/api 開頭

正確:/api/task/v2/api/tasks

錯誤:/biz/tasks/biz/api/tasks

注意:一個頁面/產(chǎn)品無論后端有多少個服務(wù)組成也應(yīng)該只有一個 API 入口

1.2 接口路徑以 api/aa-bb/cc-dd 方式命名

正確:/api/task-groups

錯誤:/api/taskGroups

1.3 接口路徑使用資源名詞而非動詞,動作應(yīng)由 HTTP Method 體現(xiàn),資源組可以進行邏輯嵌套

正確:POST /api/tasks/api/task-groups/1/tasks 表示在 id 為 1 的任務(wù)組下創(chuàng)建任務(wù)

錯誤:POST /api/create-task

1.4 接口路徑中的資源使用復(fù)數(shù)而非單數(shù)

正確:/api/tasks

錯誤:/api/task

1.5 接口設(shè)計面向開放接口,而非單純前端業(yè)務(wù)

要求:我們在給接口路徑命名時要面向通用業(yè)務(wù)而非單純前端業(yè)務(wù),以獲取篩選表單中的任務(wù)字段下拉選項為例

正確:/api/tasks

錯誤:/api/task-select-options

雖然這個接口暫時只用在表單的下拉選擇中,但是需要考慮的是在未來可能會被用在任意場景,因此應(yīng)以更通用方式提供接口交由客戶端自由組合

1.6 規(guī)范使用 HTTP 方法

方法 場景 例如
GET 獲取數(shù)據(jù) 獲取單個:GET /api/tasks/1、獲取列表:GET /api/tasks
POST 創(chuàng)建數(shù)據(jù) 創(chuàng)建單個:POST /api/tasks
PATCH 差量修改數(shù)據(jù) 修改單個:PATCH /api/tasks/1
PUT 全量修改數(shù)據(jù) 修改單個:PUT /api/tasks/1
DELETE 刪除數(shù)據(jù) 刪除單個:DELETE /api/tasks/1

其它更多請求方法請查閱 MDN Web Docs

1.7 規(guī)范使用 HTTP 狀態(tài)碼

狀態(tài)碼 場景
200 創(chuàng)建成功,通常用在同步操作時
202 創(chuàng)建成功,通常用在異步操作時,表示請求已接受,但是還沒有處理完成
400 參數(shù)錯誤,通常用在表單參數(shù)錯誤
401 授權(quán)錯誤,通常用在 Token 缺失或失效,注意 401 會觸發(fā)前端跳轉(zhuǎn)到登錄頁
403 操作被拒絕,通常發(fā)生在權(quán)限不足時,注意此時務(wù)必帶上詳細錯誤信息
404 沒有找到對象,通常發(fā)生在使用錯誤的 id 查詢詳情
500 服務(wù)器錯誤

其它更多響應(yīng)狀態(tài)碼請查閱 MDN Web Docs

1.8 基礎(chǔ)外層數(shù)據(jù)結(jié)構(gòu)

  • 不分頁數(shù)據(jù)

    {
      code: 20000,
      status: 200,
      message: "請求成功",
      data: {
        id: 1,
        name: '任務(wù) 1'
      }
    }
    
  • 分頁數(shù)據(jù)

    {
      code: 20000,
      status: 200,
      message: "請求成功",
      data: {
        items: [{
          id: 1,
          name: '任務(wù) 1'
        }, {
          id: 2,
          name: '任務(wù) 2'
        }],
        total: 2
      }
    }
    

注意:其中 code 表示業(yè)務(wù)編碼,status 表示 HTTP 響應(yīng)狀態(tài)碼,如此設(shè)計的原因是部分場景下前后端之間存在不可控的網(wǎng)關(guān)或代理(比如某些網(wǎng)關(guān)有一些流量控制策略會導致直接返回 403 響應(yīng)狀態(tài)碼,此時客戶端無法分辨 403 是網(wǎng)關(guān)的還是業(yè)務(wù)方),類似這類情況下為了能夠讓客戶端正確分辨業(yè)務(wù)方的真實處理結(jié)果則需要在響應(yīng)體加上 status,而 code 表示的業(yè)務(wù)編碼是為了幫助開發(fā)者更容易定位問題。

盡管在響應(yīng)體中體現(xiàn)了響應(yīng)狀態(tài)碼,但這并不代表所有 HTTP 就可以全部返回 200 了,無論如何請在條件允許范圍內(nèi)盡可能使用標準的 HTTP 響應(yīng)狀態(tài)碼

1.9 請求和響應(yīng)字段采用 aa_bb_cc 方式命名見名知意

// 正確
{
  role_ids: [11,12,35],
}
// 錯誤
{
  roleIds: [11, 12, 35],
  RoleIds: [11, 12, 35],
  ROLE_IDS: [11, 12, 35]
}

1.10 時間字段以 ISO 8601 格式返回 :YYYY-MM-DDTHH:MM:SSZ

1.11 常見業(yè)務(wù)字段約定

名稱:name

狀態(tài):status

創(chuàng)建時間:created_at

更新時間:updated_at

1.12 空數(shù)組使用 [],而不是 null

// 正確
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    role_ids: [],
  }
}
// 錯誤
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    role_ids: null
  }
}

1.13 前后端傳輸過程以標準 JSON 格式,避免反復(fù)正反序列化

// 正確
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    roles: [{
      id: 1,
      name: '角色 1'
    }, {
      id: 2,
      name: '角色 2'
    }]
  }
}
// 錯誤
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    roles: '[{"id":1,"name":"角色 1"},{"id":2,"name":"角色 2"}]'
  }
}

2. 創(chuàng)建類接口

2.1 創(chuàng)建完成后直接返回 id

{
  code: 20000,
  status: 200,
  message: "創(chuàng)建成功",
  data: {
     id: 1,
  }
}

2.2 關(guān)聯(lián)關(guān)系只以 id 為標識,其它字段不應(yīng)依賴客戶端

以創(chuàng)建用戶為例:POST /api/users

// 正確
{
  username: 'ming'
  password: 'xxxx',
  role_ids: [1, 2, 3]
}

// 錯誤
{
  username: 'ming'
  password: 'xxxx',
  role_ids: [{
    id: 1,
    name: '角色1'
  }, {
    id: 2,
    name: '角色2'
  }, {
    id: 3,
    name: '角色3'
  }]
}

2.3 參數(shù)錯誤以數(shù)組形式返回,并附帶用戶友好的提示

{
  code: 40000
  status: 400;
  message: "參數(shù)錯誤",
  data: {
    errors: [{
       field: 'name',
       message: '缺失'
    }]
  }
}

3. 查詢類接口

3.1 排序使用 sort 和 order

例如 GET /api/tasks?sort=created_at&order=descend 表示以創(chuàng)建時間降序查詢數(shù)據(jù)

注意:其中 orderdescend 時表示降序,為 ascend 時表示升序

3.2 分頁使用 page 和 per_page

例如 GET /api/tasks?page=1&per_page=10 表示每頁 10 條查詢第一頁數(shù)據(jù)

注意:其中 page 從 1 開始,而不是 0,如果沒有傳遞 per_pagepage 參數(shù)表示不分頁獲取所有數(shù)據(jù)

3.3 普通篩選使用鍵值對,多列模糊查詢使用 keyword 關(guān)鍵詞,枚舉篩選使用數(shù)組合并拼接,區(qū)間使用 xxx_ltxxx_gt 關(guān)鍵詞

例如 GET /api/tasks?creator=ming 表示查詢所有 ming 用戶創(chuàng)建的任務(wù)

例如 GET /api/tasks?keyword=ming 表示查詢?nèi)我饬邪?ming 關(guān)鍵詞的任務(wù)

例如 GET /api/tasks?status=pending,complete 表示查詢狀態(tài)為阻塞和完成的任務(wù)

例如 GET /api/tasks?weight_gt=10&weight_lt=20 表示查詢權(quán)重在 10 和 20 之間的任務(wù)

例如 GET /api/tasks?weight_gt=10 表示查詢權(quán)重大于 10 的任務(wù)

3.4 盡可能返回所有關(guān)聯(lián)數(shù)據(jù)展開詳情,便于客戶端顯示

{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    username: 'ming'
    roles: [{
       id: 1,
       name: '角色 1'
    }, {
       id: 2,
       name: '角色 2'
    }, {
       id: 3,
       name: '角色 3'
    }]
  }
}

3.5 可枚舉字段使用有語義英文而非無語義數(shù)字

// 正確
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    name: '任務(wù) 1'
    status: 'pending'  // 'pending' | 'complete' | 'error'
  }
}
// 錯誤
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    name: '任務(wù) 1'
    status: 0
  }
}

3.6 合理自然嵌套結(jié)構(gòu)而不是平鋪

// 正確
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    name: '任務(wù) 1'
    creator: {
      id: 1,
      username: '小明'
    }
  }
}
// 錯誤
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    name: '任務(wù) 1'
    creator_id: 1,
    creator_name: '小明'
  }
}

4. 文件類接口

4.1 統(tǒng)一提供單文件上傳接口(/api/files),支持上傳所有類型文件

// 請求,注意這里是 FormData
{
  file: File
}

// 響應(yīng)
{
  code: 20000,
  status: 200,
  message: "上傳成功",
  data: {
    id: 'bb313c99',
    url: '/files/bb313c99.pdf'
    name: '合同.pdf' // 原文件的名稱
  }
}

4.2 統(tǒng)一提供多文件上傳接口(/api/multiple-files),支持上傳所有類型文件

// 請求,注意這里是 FormData
{
  files: [File, File]
}

// 響應(yīng)
{
  code: 20000,
  status: 200,
  message: "上傳成功",
  data: [{
    id: 'bb313c99',
    url: '/files/bb313c99.pdf'
    name: '合同1.pdf' // 原文件的名稱
  }, {
    id: 'bb313c88',
    url: '/files/bb313c88.pdf'
    name: '合同2.pdf' // 原文件的名稱
  }]
}

4.3 文件路徑至少補全至根路徑

// 正確
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    name: '小明'
    avatar: '/files/bb313c99.png',
    // 或
    avatar: 'https://cdn.xxx.com/files/bb313c99.png',
  }
}
// 錯誤
{
  code: 20000,
  status: 200,
  message: "請求成功",
  data: {
    id: 1,
    name: '小明'
    avatar: 'bb313c99.png'
  }
}

4.4 對于使用到文件的接口使用文件 id 或地址而非 FormData

// 正確
{
  name: '新任務(wù) 1',
  file_id: 'bb313c99',
  // 或
  file_url: '/files/bb313c99.pdf',
}
// 錯誤
{
  name: '新任務(wù) 1',
  file: File
}

注意:先由 POST api/files 上傳完文件拿到文件 id 或地址后再執(zhí)行后續(xù)操作

5. 敏感類接口

5.1 涉及到用戶隱私的應(yīng)對相關(guān)字段做加密處理

// 正確
{
  name: '小明',
  id_number: 'U2FsdGVkX1+1fW7OpO/tlPXe4IGA/bXExlhKwIR/spk=',
  password: 'U2FsdGVkX1/AnXKSBDbztNBfp4czlZxQ++3jRtNZhY0=',
}

// 錯誤
{
  name: '小明',
  id_number: '310000199511159999',
  password: 'ming@xxx.com',
}

注意:敏感字段不要以明文形式展示。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容