1. 程式人生 > >前後端API規範參考

前後端API規範參考

規範能夠大量減少溝通成本,另外筆者認為它還有一個隱性的作用,如果有了規範,在寫程式碼的時候可以省略很多思考和修改,從而增加開發效率。所以筆者一直對規範這塊有著一種執念,總會在規範方面想很多。比如最近就在思考API的一些規範,參考RESTful API的思想,微創新出了一套過渡性的類REST規範,可以在僅用GET、POST的情況下,形成一定的規範。

下面用一個 公司列表 -> 公司詳情 -> 部門列表 的場景來舉例對比

RESTful 類RESTful 隨心所欲版
公司-查 GET /corps GET /corps GET /corps
公司-增 POST /corps POST /corps POST /corp/create
公司-刪 DELETE /corps/:corpID POST /corps/:corpID/delete POST /corp/delete
公司-改 PUT /corps/:corpID POST /corps/:corpID/put POST /corp/modify
公司-區域性改 PATCH /corps/:corpID POST /corps/:corpID/patch POST /corp/update
公司詳情-查 GET /corps/:corpID GET /corps/:corpID GET /corp
部門-查 GET /corps/:corpID/departs GET /corps/:corpID/departs GET /depart/list
部門-增 POST /corps/:corpID/departs POST /corps/:corpID/departs POST /depart/add
部門-刪 DELETE /corps/:corpID/departs/:departID POST /corps/:corpID/departs/:departID/delete POST /depart/remove
部門-改 PUT /corps/:corpID/departs/:departID POST /corps/:corpID/departs/:departID/put POST /depart/save
部門-區域性改 PATCH /corps/:corpID/departs/:departID POST /corps/:corpID/departs/:departID/patch POST /depart/change

類RESTful規範說明:

  1. 只可以在最後出現動詞
  2. 名詞要用複數
  3. “新建”時不需要動詞字尾,POST+名詞複數即可
  4. 區域性修改,如修改部門的leader、英文名等,統一用patch,修改的欄位在傳的data中宣告

如果自己的專案還有什麼特殊的需求,可適當修改為自己的規範。總之,要有一個清晰的!清晰的!清晰的!規範,來降低溝通成本,提高效率。

另外,由於類RESTful允許在最後增加動詞,這就較RESTful更為靈活,對於一些特殊的場景也可以應付自如。比如匯入、匯出、從其他資料來源同步等CURD之外的場景,就可以用不同的動詞,如import、export、sync等來進行區分。

再說說資料結構。如果有一個規範的資料結構,那麼無論對於前端還是後端來說,都有利於集中管理,封裝之後可以節省很多程式碼。

{
  "code": 200,
  "msg": "success",
  "data": {
    "corps": [
      {
        "id": 123,
        "name": "A Corp"
      }
    ],
    "corp_count": 99,
    "departs": [
      {
        "id": 456,
        "name": "A depart"
      }
    ],
    "depart_count": 49
  }
}
  1. code、msg、data必須有,且不多不少。
  2. code可簡單的定義為0、1,表示成功與否,也可參考HTTP響應碼
  3. msg為給使用者展示的資訊,可與code關聯,統一維護一個字典
  4. data必須為object,返回資料都要被其包裹。如果沒有資料返回時,至少要讓data返回一個空物件,即“{}”

最後說說前端請求的封裝。封裝後要達到以下效果:

  1. 返回結果統一處理,不用到處寫if(code===200){}else if(code===300){}之類的程式碼

  2. 封裝與業務隔離,更換其他庫的成本低,axios、jquery等說換就換,不用修改太多程式碼

  3. 支援特殊需求配置,比如成功後是否彈窗、彈窗文字變化等

  4. 支援快取,防止一些公用介面多次請求浪費資源

封裝層示意:

// ajax.js 封裝層示意
function ajaxBase(config) {
  const { url, data, type = 'get', dataType = 'json', cache = false, succuss, error } = config;
  $.ajax({
    url,
    data,
    type,
    dataType,
    cache
  }).done((res) => {
    if (res.code === 200) { // 統一成功處理
      if (succuss) {
        succuss(res.data);
      } else {
        console.log('Success!');
      }
    } else if (res.code === 302) { // 統一跳轉
      console.log('Redirect to other place!');
      location.href = data.url;
    } else { // 統一錯誤處理
      if (error) {
        error(res);
      } else {
        console.warn(JSON.stringify(res));
      }
    }
  });
}

export function getAjax(url, data, sucFun, errFun) {
  return ajaxBase({ url, data, succuss: sucFun, error: errFun });
}

export function postAjax(url, data, sucFun, errFun) {
  return ajaxBase({ url, data, type: 'post', succuss: sucFun, error: errFun });
}

封裝層是統一管理請求的地方,此處儘量封裝公共邏輯,比如上例中的預設成功回撥、失敗回撥、以及不同返回碼的回撥等。

另外一個重點是暴露。不管上面的封裝用的是jquery、axios或是其他,此處暴露出去的api傳參一定要保持不變。這樣在更換ajax核心庫的時候,後面的業務層不需要做改動。目前,效果還沒有體現出來,下面來看下業務呼叫層的情況,將會省下很多程式碼。

業務層示意:

// 業務層封裝
import { getAjax, postAjax } from './ajax.js';

export function getUsers(data, sucFun) {
  return getAjax('/users', data, sucFun);
}

export function updateUser(data, sucFun) {
  return postAjax(`/users/${data.userId}`, data, sucFun);
}


// 業務層呼叫
getUsers({ page: 1, pageSize: 10 }, ({ data }) => {
  // do success
});

// 走預設sucFun
updateUser({ userId: 123, name: 'userName' });

通常在業務層的模組裡,筆者也會做一次ajax的封裝,便於統一管理。在上例可以看到,業務層的封裝基本上就是把url傳了進去。另外,是否走cache也應該在這裡進行控制,為了不讓例子太複雜,筆者在這裡沒有體現出來,留給讀者自己實現。在最終的呼叫層可以看到,請求變得清晰簡單許多。

對於promise風格的封裝,可能就有些不同了,不過思路都是一樣的,只要能達到上面總結的各種效果,就是好的封裝。