都2023了,不会有人手撸API函数吧
如果你正在开发一个前端程序,后端有指定规范的 API, 那你该看看这篇文章啦~
本文章示例用到了TypeScript,如果觉得不适,看一下核心代码即可。
业务场景举例
API 通常是提供在不同实体上执行增删改查(CRUD)造作的一组接口。我们通常在我们的前端项目中为这些每一个接口提供一个函数,这些函数的功能非常的相似,只是为了服务于不用的实体。举个例子,假设我们有这些函数。
// api/user.ts
import http from '@/utils/http';
// 登录参数
export interface LoginData {
/** 登陆编码 */
loginCode: string;
password: string;
}
/** 用户信息 */
export interface UserInfo {
/** 状态 */
status: string;
/** 创建人 */
createBy: string;
/** 创建时间 */
createDate: string;
/** 更新人 */
updateBy: string;
/** 更新时间 */
updateDate: string;
remarks: string | null;
/** 用户编码 */
userCode: string;
/** 登陆编码 */
loginCode: string;
/** 用户名 */
userName: string;
/** 密码 */
password: string;
/** 邮件 */
email: string;
/** 手机 */
mobile: string | null;
/** 电话 */
phone: string | null;
/** 性别 */
sex: string;
/** 头像 */
avatar: string | null;
/** 个性签名 */
sign: string | null;
/** 微信开发id */
wxOpenId: string | null;
/** 手机imei */
mobileImei: string | null;
/** 用户类型 */
userType: string;
/** 用户类型引用编号 */
refCode: string | null;
/** 用户类型引用名称 */
refName: string | null;
/** 管理员类型 */
mgrType: string;
/** 密码强度等级 */
pwdSecurityLevel: string | null;
/** 用户权重 */
userWeight: number;
}
/** 登录信息 */
export interface LoginInfo {
tokenName: string;
tokenValue: string;
isLogin: boolean;
loginId: string;
loginType: string;
tokenTimeout: number;
sessionTimeout: number;
tokenSessionTimeout: number;
tokenActivityTimeout: number;
loginDevice: string;
tag: string;
}
export interface LoginRes {
loginInfo: LoginInfo;
userInfo: UserInfo;
}
/** 登录接口 */
export function login(data: LoginData) {
return http.post<LoginRes>({
url: '/login', data });
}
/** 登出接口 */
export function logout() {
return http.post<null>({
url: '/logout' });
}
/** 获取当前登录的用户信息 */
export function getLoginUserInfo() {
return http.get<UserInfo>({
url: '/loginUserInfo' });
}
/** 获取当前登录信息 */
export function getTokenInfo() {
return http.get<LoginInfo>({
url: '/tokenInfo' });
}
类似的功能可能存在于其他实体,例如:角色、权限、用户...但是我们可以用一个简单的函数调用来代替这些函数:
// api/system-privilege/users.ts
import {
ServiceProxy } from '@/shared';
import {
UserInfo } from '@/api/user';
import {
ListDataRes } from '@/api/common';
// 参数接口
export interface ListDataParams {
userName?: string;
}
export interface SaveParams {
userCode?: string;
loginCode: string;
userName?: string;
mobile?: string;
email?: string;
sex?: string;
sign?: string;
userType: string;
userWeight: number;
mgrType: string;
}
// 核心
const service = new ServiceProxy('/api/sys/user');
/**
* 获取用户列表
* @param {object} params ListDataParams
* @param {string} params.userName
* @returns
*/
export function getPaged(
params: ListDataParams
): Promise<ListDataRes<UserInfo>> {
return service.getPaged(params);
}
/**
* 修改或新增用户
* @param {object} params 用户保存实体
* @param {string} params.userCode 用户编码,用户id,为空则新增,不为空则修改
* @param {string} params.loginCode 登陆编码,用户登陆的账号
* @param {string} params.userName 用户名
* @param {string} params.mobile 手机
* @param {string} params.email 邮件
* @param {string} params.sex 性别
* @param {string} params.sign 个性签名
* @param {string} params.userType 用户类型
* @param {number} params.userWeight 用户权重
* @param {string} params.mgrType 管理员类型
* @returns
*/
export function createOrUpdate(params: SaveParams): Promise<null> {
return service.createOrUpdate(params);
}
/**
* 获取用户信息
* @param {string} params.id 类型主键
* @returns
*/
export function getById(params: {
id: string }): Promise<null> {
return service.getById(params);
}
/**
* 获取用户信息
* @param {string} params.id 类型主键
* @returns
*/
export function del(params: {
id: string }): Promise<null> {
return service.delete(params);
}
然后像这样去使用:
import {
getPaged, createOrUpdate, getById } from '@/api/system-privilege/users';
// 一下返回的是Promise
getPaged({
...params.res, pageNum: params.pageNum, pageSize: params.pageSzie });
createOrUpdate(state.data);
getById({
id: props.id })
你可能会问为什么?有一些很好的理由:
- 减少了代码行数:你编写的代码,和当你离开公司时其他人维护的代码
- 强制执行 API 函数的命名约定,这可以增加代码的可读性和可维护性
- 同时
ServiceProxy
的实现使用的 class,当API不符合要求时,可以通过继承等方式进行扩展(业务场景:对接第三方接口)。
此处ServiceProxy
就类似于一个高级可扩展的 CRUD 构造器。
高级构造器 ServiceProxy 的实现
以下便是ServiceProxy
基础实现,如果觉得简单,是可以进行增强和扩展的哟。
import http from '@/utils/http';
import VAxios from '@/utils/http/Axios';
export default class ServiceProxies {
private instance: VAxios;
private baseUrl: string;
private url: string;
constructor(url?: string, baseUrl?: string, instance?: VAxios) {
this.instance = instance || http;
this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : '';
this.url = url !== undefined && url !== null ? url : '';
}
/**
* 获取列表数据
* @returns
*/
getPaged<T>(params: T) {
return this.instance.post({
url: this.url, data: {
...params } });
}
/**
* 通过ID获取详细信息
* @returns
*/
getById<T>(params: T) {
return this.instance.get({
url: this.url, params: {
...params } });
}
/**
* 通过拼接构造器与传入的api进行Get请求,类似扩展构造器的url
* @param api 扩展api
* @param params 参数值
*/
getApi(api: string, params: any) {
return this.instance.get({
url: `${this.url}${api}`,
params: {
...params },
});
}
/**
* 通过拼接构造器与传入的api进行Post请求,类似扩展构造器的url
* @param api 扩展api
* @param params 参数值
*/
postApi(api: string, params: any) {
return this.instance.post({
url: `${this.url}${api}`,
data: {
...params },
});
}
/**
* 通过拼接构造器与传入的api进行Put请求,类似扩展构造器的url
* @param api 扩展api
* @param params 参数值
*/
putApi(api: string, params: any) {
return this.instance.put({
url: `${this.url}${api}`,
data: {
...params },
});
}
/**
* 通过拼接构造器与传入的api进行Delete请求,类似扩展构造器的url
* @param api 扩展api
* @param params 参数值
*/
deleteApi(api: string, params: any) {
return this.instance.delete({
url: `${this.url}${api}`,
params: {
...params },
});
}
/**
* 新增或者编辑
* @returns
*/
createOrUpdate<T>(params: T) {
return this.instance.put({
url: this.url, params: {
...params } });
}
}
用法:
import {
ServiceProxy } from '@/shared';
const service = new ServiceProxy('/api/sys/user');
const service = new ServiceProxy('/api/sys/role');
const service = new ServiceProxy('/api/sys/menu');
// 然后再去编写业务逻辑代码
// 相关示例可以观看上述的用户示例
结尾
看到这里小伙伴们是不是有一种发现新大陆的感觉。
快动动你们的小手指敲起来吧~
当然,如果觉得有什么不合理的地方,可以指出来哦。