如何实现从后端“接口文档”到前端“API函数”的自动化编码?
前端不再需要手动管理“API函数层”的代码,开发者只需要关注业务代码,可以做到“无感知”接口的存在。
文字的描述可能不太好理解,我们先来体验一下具体的使用场景吧。
快速体验
假设我们前端项目的API层代码是这样的:
// /api/user.ts
import request from '@/api/request';
import { CreateUser, User } from './models';
/**
* 创建用户
* @param user
* @returns
*/
export function create(user: CreateUser) {
return request<User>({
url: '/api/user/create',
method: 'post',
data: user,
});
}// /api/models/CreateUser.ts
/**
* 创建用户信息模型
*/
export default interface CreateUser {
/** 姓名 */
name: string;
/** 年龄 */
age: number;
}// /api/models/User.ts
/**
* 用户信息模型
*/
export default interface User {
/** 姓名 */
name: string;
/** 年龄 */
age: number;
/** 角色 1.管理员 2.普通用户 */
role: number;
// ...
}// /api/models/index.ts
export * as CreateUser from './CreateUser.ts';
export * as User from './User.ts';我们在业务代码中通常会这样使用:
import * as userApi from '@api/user';
// 省略其他代码
const userData = await userApi.create({
name: '张三',
age: 35,
});
// 判断用户角色
console.log(userData.role === 1);我们可以看到,API层的代码其实是“非常繁琐”的。你不仅需要对每一个接口写一个API函数,还需要写一大堆的数据模型TypeScript定义。
在实际开发中,可能很多开发者都是直接使用any代替了数据模型的定义,这对后期接口维护时会带来很大的负担。一旦接口字段变了,还可能会引起前端项目一些隐藏的bug。
那么试想一下,所有API层的代码都是根据后端接口文档来写的,那为什么不能用一款工具来帮我们自动完成这一步呢?
对于开发者来说,调用接口最理想的方式是:根本不用关心API层面的代码,只需要“拿来使用”即可。
因此,我们可能需要这样一款工具:
- 📌 输入后端符合OpenAPI规范的“接口文档”
- 📌 根据文档自动生成API函数和数据模型定义
- 📌 接口变更后支持同步更新
- 📌 可以很方便地集成到项目中去
- 📌 不要改变现有的编码习惯
现在,我们就将此工具命名为:UnoAPI。
以后,你的项目可能并不需要API层了。它没有真正地干掉API层的代码,而是可以让开发者做到“无感知”API层的存在。
工作方式
虽然名字上与“UnoCSS”很相似,但它们的工作方式完全不一样:
- **UnoCSS 是“先使用,后生成”:**它会根据你写的class类名,然后生成相应的CSS样式;
- 而**UnoAPI必须是“先生成,后使用”:**它必须先生成API层的代码,然后才能使用,这必须符合我们的编码直觉和规范。
为什么UnoAPI必须是“先生成,后使用”?
因为你不可能调用一个“不存在”的函数以此来欺骗代码的正确性验证,这显然不符合编码逻辑。
但也不尽然!
我们完全可以先只生成TypeScript类型定义部分的代码,具体的实现我们也可以根据“先使用,后生成”的逻辑,来最小化生成我们的API层代码。
但是这样做又有多大的意义呢?
就为了使生成的代码最小化?但是现在的打包工具对Tree Shaking已经做得够好了,我们只需要生成符合Tree Shaking规范的API层代码就行了。
使用方式
为了得到更好的使用体验,我们可以参考Eslint工具的使用方式。
- 安装依赖包
- 在项目根目录定义配置文件
- 支持命令行进行操作
- 支持VS Code扩展操作
所以UnoAPI可以拆分成3个模块:
- ✅️ 核心层:@unoapi/core;
- ✅️ cli模块:@unoapi/cli;
- ⭕️ VS Code扩展:@unoapi/vscode-extension;
为了体验到完整的功能,核心层与cli模块是必须的,VS Code扩展可以作为后期目标,提升用户体验。
我们先从使用的角度,将UnoAPI进行一个大致的设计:
1. 安装依赖包
npm i @unoapi/core @unoapi/cli -D2. 定义配置文件
我们将配置文件命名为:unoapi.config.js,通过命令行一键生成初始配置:
uno init
# 在根目录生成 unoapi.config.js 默认配置我们必须在配置文件中指定接口文档的OpenAPI地址,支持配置输出目录、
3. 生成API层代码
uno api url1,url2,url3根据接口的URL路径生成对应的API层代码,这里需要对URL格式进行一定的规范。
URL格式:模块1/模块2/.../动作
- 模块路径:决定了默认的目录和文件名称
- 动作:生成默认的API函数名称
比如: /project/group/getList 和 /project/group/create,生成的API函数是这样的:
// /api/project/group.ts
export function getList() {
// ...
}
export function create() {
// ...
}对于不遵守此规范的URL,或者不想使用默认行为的,我们也需要支持自定义配置。
uno api api/v2/aabbcc -o project/group.ts --func createProjectGroup生成的API函数:
// /api/project/group.ts
export function createProjectGroup() {
return request({
url: 'api/v2/aabbcc'
})
}为了更好的体验,我们可能还需要支持更多的操作命令,以及更加灵活的配置。但是这里先不讨论太细节的东西,我们只需要对UnoAPI设计一个大概的雏形即可。
持续更新
我创建了一个合集「UnoAPI工具篇」,这个系列将会持续更新。
在这个合集中,我将和大家一起来实现UnoAPI,共同见证一下它到底好不好用!