前阵子帮几个项目接后端 API,代码库里到处都是风格不一的请求封装:有的直接手写 fetch,有的半自动生成,有的还混着好几版接口。弄了一堆没人敢碰的"神圣代码",动一点就怕出生产事故。最后我干脆写了个小框架,就是现在的 genapi。
- Docs:genapi-docs.vercel.app/
- Playground:genapi-docs.vercel.app/playground
- GitHub:github.com/hairyf/gena...
手写 VS 传统代码生成 VS genapi
-
手动编写 API
好处是完全可控,想怎么写就怎么写,也最贴合项目风格;问题是接口一多,代码重复、命名不统一、漏改一个字段就要线上排查半天。
-
传统代码生成器
好处是类型安全、一次性全生成,很多还支持自定义模板;但经常会顺带送你一整套运行时和抽象层,函数名、目录结构都被"设计好"了,和现有项目不太对味。模板虽然能改,但门槛不低,团队里最后往往只剩一个人敢碰。
-
genapi 的路子
genapi 只做一件事:从数据源生成"长得像你自己手写"的 API 代码。它不强行塞运行时,不要求你接受一整套工程哲学,而是把生成过程拆成可组合的 pipeline / transform / mapping,让你在"完全手写"和"被框架锁死"之间,找到一个舒服的中间态。
genapi 想做的事,很简单
一句话概括:一个轻量的 API 代码生成器------只生成你真正需要的代码。
它有几个核心设计思路:
-
尽量贴近你平时手写的代码风格
生成出来的就是普通的
axios/fetch/ofetch/tanstack-query调用函数,你看一眼就能改,甚至可以直接当手写模板来抄。 -
不强推运行时框架
genapi 更像是一个"代码 printer":给它 OpenAPI/Swagger 文档,它吐出一堆很正常的 TS/JS 文件,没有私货,没有黑盒运行时。
-
生成过程是可定制的 pipeline
你可以在 pipeline 里插各种"transform"和"patch":比如统一加上
/api前缀、重命名某些路径、批量改类型、对个别接口做精确替换。 -
既能 TS 也能 JS,类型一视同仁
同时生成 TS 源码和
.d.ts类型文件,团队里有人用 JS 也能享受完整的类型提示和 IntelliSense。 -
支持多种 HTTP 客户端和 schema 模式
除了
axios、fetch、ky、got、ofetch、tanstack-query等常规客户端,还提供基于schema的类型安全 fetch 预设,适合喜欢自己包一层 HTTP 的同学。
一个最小可用示例:从 OpenAPI 到可用的 axios API
安装依赖(推荐用 pnpm,也支持 npm / yarn):
bash
# 推荐
pnpm dlx @genapi/core genapi init
# 或者手动安装
pnpm add @genapi/core @genapi/presets -D
创建一个最简单的 genapi.config.ts:
ts
import { defineConfig } from '@genapi/core'
import { axios } from '@genapi/presets'
export default defineConfig({
preset: axios.ts,
input: 'https://petstore3.swagger.io/api/v3/openapi.json',
output: {
main: 'src/api/index.ts',
type: 'src/api/index.type.ts',
},
})
然后直接跑:
bash
npx genapi
生成出来的代码大概长这样(节选):
ts
import type { AxiosRequestConfig } from 'axios'
import type * as Types from './index.type'
import http from 'axios'
/**
* @summary Update an existing pet.
* @description Update an existing pet by Id.
* @method put
* @tags pet
*/
export function putPet(data?: Types.Pet, config?: AxiosRequestConfig) {
const url = '/pet'
return http.request<Types.Pet>({ method: 'put', url, data, ...config })
}
如果你项目里已经有一套封装好的 request 实例,只需要在 preset 或 pipeline 里替换 http 的引入和调用方式,就能无缝接上现有代码。
Schema 模式:类型驱动的 fetch
除了传统的"按接口生成一堆函数",genapi 还内置了 schema 模式的 preset,更适合那些已经有一层 HTTP 封装、只想让它真正类型安全 的项目。 核心思路是:你先声明一份纯类型的 API Schema,然后只实现一次带泛型的 $fetch:
ts
// API Schema
interface APISchema {
'/users': {
[Endpoint]: {
GET: {
response: Types.User[]
}
}
}
}
export async function $fetch<T extends TypedFetchInput<APISchema>>(
input: T,
init?: TypedFetchRequestInit<APISchema, T>,
) {
return fetch(input, init as any) as Promise<
TypedResponse<TypedFetchResponseBody<APISchema, T>>
>
}
genapi 会根据 APISchema 生成类型约束和辅助类型,你在业务代码里写 $fetch('/users') 的时候,请求参数和返回值就都自动带上了精确的类型;而当你改了 schema 或 mapping 之后,类型会跟着一起更新。
适合哪些项目用 genapi?
-
有 OpenAPI/Swagger 文档,但不想被"官方生成器"绑架的团队
想要类型安全、规范化 API,又希望生成的代码看起来像自己写的。
-
多端、多 HTTP 客户端的项目
Web 用
axios,小程序用uni-network,服务端用ofetch,都可以通过不同 preset 一次性生成。 -
需要长期维护的中大型前端仓库
接口多、改动频繁,用 genapi 把"接口签名"部分自动化,让人力更专注在业务和状态管理上。
如果你只是一个 demo 项目,手写几行 fetch 也没什么问题;但一旦接口数量上来、版本反复变更,自动化生成就会慢慢变成刚需。
不只有 Swagger:genapi 的扩展性
虽然最常见的输入是 OpenAPI 2.0/3.x、Swagger 这类规范文档,但 genapi 的内核其实只关心一件事:给我一份可以描述"有哪些接口、参数和返回值"的结构化数据。
这意味着:
- 你可以自己写一个小转换,把后端现有的接口列表(哪怕是一个 Excel、一个内网 JSON)先转成中间格式,再丢给 genapi;
- 也可以从其它系统(比如 wpapi、内部网关、BFF 配置)拉元数据,做一层适配,就能享受同一套生成能力;
- 真正做定制的时候,不需要 fork genapi 本身,而是通过"数据源适配器 + pipeline/transform/mapping"把你们的接口信息结构化输出。
换句话说:只要你能把接口信息结构化输出,genapi 基本都能搞定。
写在最后
我对 genapi 的期待其实很朴素:它不要把你的项目变成"genapi 风格",而是安静地融进你现有的代码库。
如果你也在用 OpenAPI,却一直没找到顺手的代码生成工具,不妨抽个时间试一下:
bash
pnpm dlx @genapi/core genapi init
用完有任何想法或吐槽,欢迎来 GitHub 开个 issue 或 PR。