前后端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风格的封装,可能就有些不同了,不过思路都是一样的,只要能达到上面总结的各种效果,就是好的封装。

猜你喜欢

转载自blog.csdn.net/zhaolandelong/article/details/81165541