前端API层架构,也许你做得还不够 (2)

首先,为了对齐后端微服务架构,在前端将API调用分为三个模块。

├─api index.js axios底层封装 ├─base 负责调用基础服务,basecenter ├─iot 负责调用物联网服务,iotcenter └─user 负责调用用户相关服务,usercenter

每个模块下都定义了统一的微服务命名空间,例如/src/api/user/index.js:

export const namespace = 'usercenter'; 特性模块

每个功能特性都有独立的js模块,以角色管理相关接口为例,模块是/src/api/user/role.js

import api from '../index' import { paramsFilter } from "@/utils/helper"; import { namespace } from "./index" const feature = 'role' // 添加角色 export const addRole = params => api.post(`/${namespace}/${feature}/add`, paramsFilter(params)); // 删除角色 export const deleteRole = id => api.deletes(`/${namespace}/${feature}/delete`, { id }); // 更新角色 export const updateRole = params => api.put(`/${namespace}/${feature}/update`, paramsFilter(params)); // 条件查询角色 export const findRoles = params => api.get(`/${namespace}/${feature}/find`, paramsFilter(params)); // 查询所有角色,不传参调用find接口代表查询所有角色 export const getAllRoles = () => findRoles(); // 获取角色详情 export const getRoleDetail = id => api.get(`/${namespace}/${feature}/detail`, { id }); // 分页查询角色 export const getRolePage = params => api.get(`/${namespace}/${feature}/page`, paramsFilter(params)); // 搜索角色 export const searchRole = params => params.keyword ? api.get(`/${namespace}/${feature}/search`, paramsFilter(params)) : getRolePage(params);

每一条接口都根据RESTful风格,调用增(api.post)删(api.deletes)改(api.put)查(api.get)的底层方法,对外输出语义化方法。

调用的url由三部分组成,格式:/微服务命名空间/特性命名空间/方法

接口适配层函数命名规范:

新增:addXXX

删除:deleteXXX

更新:updateXXX

根据ID查询记录:getXXXDetail

条件查询一条记录:findOneXXX

条件查询:findXXXs

查询所有记录:getAllXXXs

分页查询:getXXXPage

搜索:searchXXX

其余个性化接口根据语义进行命名

解决问题

语义化程度更高,配合vscode的代码提示功能,用起来不要太爽!

迅速响应接口改动,适配层统一处理

集中进行数据处理(对于公用的数据处理,我们用paramsFilter解决,对于特殊的情况,再另行处理),调用者安心做业务即可

满足特殊场景,佛系应对后端和产品朋友

针对上节提到的关键字查询场景,我们在适配层通过在入参中判断是否有keyword字段,决定调用search还是page接口。对外我们只需暴露searchRole方法,调用者只需要调用searchRole方法即可,无需做其他考虑。

export const searchRole = params => params.keyword ? api.get(`/${namespace}/${feature}/search`, paramsFilter(params)) : getRolePage(params);

针对产品突然加的排序需求,我们可以在适配层去做默认入参的处理。

首先,我们新建一个专门管理默认参数的js,如src/api/default-options.js

// 默认按创建时间降序的参数对象 export const SORT_BY_CREATETIME_OPTIONS = { sortField: 'createTime', // desc代表降序,asc是升序 sortType: 'desc' }

接着,我们在接口适配层做集中化处理

import api from '../index' import { SORT_BY_CREATETIME_OPTIONS } from "../default-options" import { paramsFilter } from "@/utils/helper"; import { namespace } from "./index" const feature = 'role' export const getRolePage = params => api.get(`/${namespace}/${feature}/page`, paramsFilter({ ...SORT_BY_CREATETIME_OPTIONS, ...params }));

SORT_BY_CREATETIME_OPTIONS放在前面,是为了满足如果出现其他排序需求,调用者传入的排序字段能覆盖掉默认参数。

mock先行

一个完善的API层设计,肯定是离不开mock的。在后端提供接口之前,前端必须通过模拟数据并行开发,否则进度无法保证。那么如何设计一个跟真实接口契合度高的mock系统呢?我这里简单做下分享。

首先,创建mock专用的axios实例

我们在src目录下新建mock目录,并在src/mock/index.js简单封装一个axios实例

// 仅限模拟数据使用 import axios from "axios" const mock = axios.create({ baseURL: '' }); // 返回状态拦截 mock.interceptors.response.use( response => { return Promise.resolve(response.data) }, error => { return Promise.reject(error.response) } ) export default mock

mock同样也要分模块,以usercenter微服务下的角色管理mock接口为例

├─mock index.js mock底层axios封装 ├─user 负责调用基础服务,usercenter ├─role ├─index.js

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjfpd.html