我受够了混乱的 API 代码,所以我写了个框架

前阵子帮几个项目接后端 API,代码库里到处都是风格不一的请求封装:有的直接手写 fetch,有的半自动生成,有的还混着好几版接口。弄了一堆没人敢碰的"神圣代码",动一点就怕出生产事故。最后我干脆写了个小框架,就是现在的 genapi

手写 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 模式

    除了 axiosfetchkygotofetchtanstack-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。

相关推荐
小徐_23331 小时前
向日葵 x AI:把远程控制封装成 MCP,让 AI 替我远程控制设备
前端·人工智能
冴羽1 小时前
来自顶级大佬 TypeScript 之父的 7 个启示
前端·typescript
leafyyuki2 小时前
在 Vue 项目中玩转 FullCalendar:从零搭建可交互的事件日历
前端·javascript·vue.js
决斗小饼干2 小时前
低代码平台工作流引擎设计:从状态机到智能流转的技术演进
前端·低代码·工作流引擎
豆苗学前端2 小时前
彻底讲透浏览器缓存机制,吊打面试官
前端·javascript·面试
米丘2 小时前
了解 window.history 和 window.location, 更好地掌握 vue-router、react-router单页面路由
前端
swipe2 小时前
箭头函数与 this 面试题深度解析:从原理到实战
前端·javascript·面试
星_离3 小时前
《Vue 自定义指令注册技巧:从手动到自动,效率翻倍》
前端·vue.js
狗头大军之江苏分军3 小时前
消耗 760万 Token 后,一文看懂了“小龙虾” OpenClaw 和 OpenCode 的区别
前端·后端