你还在自己写接口或者接口类型吗?

前言

作为前端开发,我们在开发中,能不能不再关注接口层面的东西,比如:编写接口函数,接口的参数处理(queryString参数,路径参数,FormData参数),或者使用TS的时候还得接口类型。有没有一些工具或者能自动处理这些?

答案是肯定的,@api-helper/cli 来了。

为什么选择它?已经存在了其他工具,也能达到这些功能,比如:

  • yapi-to-typescript
  • swagger-typescript-api
  • @umijs/openapi

经过测试,他们或多或少存在一些问题

比如:它们需要严格注释规范,例如dot字段解析,当后端定义一个字段:userInfo.name 在它们的解析规则里面这种是直接解析成"userInfo.name",整体作为一个字段,而@api-helper/cli会将userInfo解析成一个对象,name是它的属性,更符合参数定义,当然也支持Array类型。

在其他方面yapi-to-typescript 在openapi3.1版本中生成失败;@umijs/openapi 不兼容openapi2版本;swagger-typescript-api需要相对严格的格式,vo类不能出现非英文字符,否则会报错,接口如果存在使用query接受动态参数也会容易出错,前端解析后会出现$字符导致解析失败。

不可否认的是,他们也是有很多优点,比如@umijs/openapi可以根据分类生成单文件接口,@api-helper/cli 和 yapi-to-typescript 采用同样的策略,所有接口类型都在一个文件中,存在问题是单文件过大,但是现代构建工具,支持treeShaking功能,这种情况下,@api-helper/cli 能做分类生成单文件生成接口,但是没必要。

@api-helper/web 还提供了web页面,操作选择接口,字段,生成想要的代码,在web服务中,自定义模版,生成任何想要的代码。以及对请求参数的校验等功能、mock数据生成等等功能。

@api-helper/cli

  • 内置解析:openapi(swagger)、yapi
  • 支持openapi2.0、openapi3.0 以及最新的 openapi3.1 版本

开始

  1. 安装依赖:pnpm i @api-helper/cli

  2. 安装完成之后,使用指令生成配置文件 npx apih init

  3. 编辑生成的配置文件,填写接口文档地址。

js 复制代码
import { defineConfig } from '@api-helper/cli';

export default defineConfig({
  // 输出文件路径,会根据后缀名(.js|.ts)判断是生成TS还是JS文件
  outputFilePath: 'src/api/index.ts',
  // 接口请求函数文件路径
  requestFunctionFilePath: 'src/api/request.ts',
  // 接口文档服务配置
  documentServers: [
    {
      // 文档地址【当下面的type为swagger类型时,可以读取本地文件,这里就是一个本地文件路径】
      url: 'http://接口文档地址',
      // 文档类型,根据文档类型,调用内置的解析器,默认值: 'swagger'【内置yapi和swagger的解析,其他文档类型,添加parserPlugins自行实现文档解析】
      type: 'swagger',
      // 获取数据的key,body[dataKey]
      dataKey: '',
    },
  ],
});
  1. 最后使用指令生成即可:npx apih

更多配置参考:官方文档

生成后代码

  • src/api/index.ts

如果生成的代码是index.js,会自动增加一个文件名称相同,后缀名为.d.ts的文件,该文件包含了接口的类型定义,写JS的也有类型提示。

请求调用中内置的 processRequestFunctionConfig 会自动处理queryParams参数,路径参数,FormData参数。

ts 复制代码
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore-start */

/* 代码生成时间: 2024-04-03 18:37:33 */
/* 提示:该文件由 API Helper CLI 自动生成,请勿直接修改。 */
/* 文档参考:https://github.com/ztz2/api-helper/blob/main/packages/cli/README.md */

// @ts-ignore
// prettier-ignore
import {
  RequestFunctionRestArgsType,
  processRequestFunctionConfig,
} from '@api-helper/cli/lib/helpers';
// @ts-ignore
// prettier-ignore
import request from './request';
// @ts-ignore
// prettier-ignore
type CurrentRequestFunctionRestArgsType = RequestFunctionRestArgsType<typeof request>;

/**
 * @description 账户登录、账户登录【请求数据类型定义】
 * @url [ POST ] /api/{nickName}/auth
 */
export interface ApiNickNameAuthRequestByPost {
  // 图形验证码结果
  code?: string;
  // 密码密文(认证类型password必传)
  password?: string;
  // 手机号
  phone: string;
  // 授权范围,默认填all
  scope?: string;
  // 短信验证码结果
  smsCode?: string;
  // 登录机构ID
  tenantId?: string;
  // 账户名
  username: string;
  // 图形验证码key
  uuid?: string;
}
/**
 * @description 账户登录、账户登录【响应数据类型定义】
 * @url [ POST ] /api/{nickName}/auth
 */
export interface ApiNickNameAuthResponseByPost {
  // TokenResponseVO
  // 授权令牌
  accessToken: string;
  // 当前登录机构ID
  currentTenant: number;
  // 账户昵称
  nickName: string;
  // 权限集合,登录成功返回
  permissions: Array<string>;
  // 登录确认令牌,若存在多机构不直接返回accessToken,通过SubmitToken确认登录机构
  submitToken: string;
  // 账户关联机构
  tenants: Array<// TenantBO
  {
    id: number;
    lastLoginTime: string;
    tenantCode: string;
    tenantName: string;
  }>;
  // 登录类型,1:账号密码,2:短信验证码
  type: number;
  // 账户ID
  userId: number;
  // 账户类型,0:管理用户,1:机构用户
  userType: number;
  // 账户名
  username: string;
}
/**
 * @description 账户登录、账户登录
 * @url [ POST ] /api/{nickName}/auth
 */
export function apiNickNameAuthByPost(data: ApiNickNameAuthRequestByPost, extraData?: unknown, ...args: CurrentRequestFunctionRestArgsType) {
  return request<ApiNickNameAuthResponseByPost>(
    processRequestFunctionConfig(data, extraData, apiNickNameAuthByPost.requestConfig),
    ...args
  );
}
apiNickNameAuthByPost.requestConfig = {
  path: '/api/{username}/auth',
  method: 'POST',
  formDataKeyNameList: [],
  pathParamKeyNameList: ['username'],
  queryStringKeyNameList: [],
};
  • src/api/request.ts 如果没有创建request.ts会自动创建

由于processRequestFunctionConfig处理了请求参数,在request函数中的config.path也会有所变化,比如:如果存在queryParams参数(userID),路径参数等,此时config.path将会变成/api/xxx/auth?userID=xxx。而存在FormData参数时候,config.hasFormData的值会为true,与之对于的config.data会变成new FormData()对象(兼容Nodejs,小程序或者不支持FormData实例的环境会忽略这个处理)。

这些前置性的处理,可以就让实现具体请求的时候,变得更加简单方便。

ts 复制代码
import { RequestFunctionConfig } from '@api-helper/cli/lib/helpers';

// 自定义配置
export type RequestOptions = {};

export default async function request<ResponseData>(config: RequestFunctionConfig, options?: RequestOptions): Promise<ResponseData> {
  return new Promise((resolve, reject) => {
    // 以axios为例的请求配置
    const requestConfig = {
      url: config.path,
      method: config.method,
      data: config.data,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    };
    // 处理表单数据请求头
    if (config.hasFormData) {
      requestConfig.headers['Content-Type'] = 'multipart/form-data';
    }
    
    /**
     * TODO待实现具体request请求逻辑...
     * 基于axios实现具体请求的简单例子
       axios(requestConfig).then((res) => {
          resolve(res as unknown as ResponseData);
       }).catch(reject);
     */
    // 先用异步模拟request请求逻辑
    setTimeout(() => {
      resolve({} as unknown as ResponseData);
    }, 1500);
  });
}

调用接口

ts 复制代码
import { apiNickNameAuthByPost } from '@/api';

apiNickNameAuthByPost({ username: 'xxx', phone: 'xxx' }).then((data) => {
  console.log(data)
});

web服务

web服务提供了基于接口的自定义代码生成,使得代码生成更加具有灵活性,在介绍该功能之前,先简单说明API Helper的项目分包。@api-helper/cli 提供接口生成功能以及这里的web服务都是基于@api-helper/core和@api-helper/template实现。

  • @api-helper/cli 该包提供了apih指令,用于接口生成。
  • @api-helper/core 是解析接口文档的核心包。
  • @api-helper/template 模版包,内置了class模版,ts类型模版,JS对象模版。
  • @api-helper/web 该包提供web服务的前端操作页面。
  • @api-helper/server 该包提供web服务的Server端。

启动web服务

  • 下载整个仓库代码:git clone https://github.com/ztz2/api-helper.git
  • 如果是windows环境,并且安装了 pnpm,鼠标双击项目run-web-server.bat脚本文件即可。

手动启动步骤

  1. 打包浏览器代码,进入web包下,输入命令:pnpm run build
  2. 打包服务器端代码,进入server包下,输入命令:pnpm run build
  3. 启动服务,进入server包下,输入命令:pnpm run start:prod
    • 服务启动后访问地址:http://localhost:3210
    • 如果需要更新最新代码运行,需要从步骤1开始,后续启动服务操作,都是步骤3。

启动成功后,代码该地址界面如下,点击添加,根据提示,填写接口文档地址。

接口请求参数校验功能

该功能用于校验请求参数是否缺少字段,必填项是否缺少值,支持queryParams参数和对象类型识别。在接口调试时,谷歌浏览器中,按下F12 -> network 找到对应的请求,复制该请求的paylod参数,直接丢进来即可检查是否缺少字段,结果一目了然,不能让锅留给前端一点点机会。

生成class、js对象

生成的代码,有对应的注释类型,字段label等。

生成表单模版等

mock数据生成

上面模版都是系统内置模版,自定义模版可以点击新增模版,或者编辑系统内置模版,参考内置模版语法,编写属于自己的的自定义模版。

web服务提供了基本的请求&响应参数对象展示,一定程度上可以代替接口文档。

最后

简单总结一下,接口层面的代码,直接交给@api-helper/cli。web服务提供的功能,可以生成JS对象、JS类、mock数据以及表单模版代码。表单模版代码,在C端管理信息系统中,特别的好用,抽离出管理系统的表单代码,然后基于它自定义模版,每次生成的表单代码,接口字段都绑定好了,这不香?如果把模版功能运用熟悉了,可以把一个功能模块的(增删改查)都定义成模版,在web服务中有一个文件模块生成的功能,它可以绑定模版与接口关联,然后生成整个模块的代码文件,创建文件的过程也可以省略了。

相关推荐
y先森22 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy22 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu108301891125 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿2 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡2 小时前
commitlint校验git提交信息
前端
虾球xz3 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇3 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端