都2023了,不会有人手撸API函数吧

139 阅读4分钟

都2023了,不会有人手撸API函数吧

如果你正在开发一个前端程序,后端有指定规范的 API, 那你该看看这篇文章啦~

本文章示例用到了TypeScript,如果觉得不适,看一下核心代码即可。

业务场景举例

API 通常是提供在不同实体上执行增删改查(CRUD)造作的一组接口。我们通常在我们的前端项目中为这些每一个接口提供一个函数,这些函数的功能非常的相似,只是为了服务于不用的实体。举个例子,假设我们有这些函数。


// api/user.tsimport 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.tsimport { 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';
​
// 一下返回的是PromisegetPaged({ ...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');
​
// 然后再去编写业务逻辑代码
// 相关示例可以观看上述的用户示例

结尾

看到这里小伙伴们是不是有一种发现新大陆的感觉。

快动动你们的小手指敲起来吧~

当然,如果觉得有什么不合理的地方,可以指出来哦。