前端动态 API 生成与封装:前端 API 调用的一种思路

前端动态 API 生成与封装:前端 API 调用的一种思路

引子

在前端开发中,排除部分使用graphql的场景,一般还是需要调用大量的后端接口。传统的做法是手动编写每个 API 调用函数,或者使用像 Swagger Codegen 这样的工具生成客户端代码。但这两种方式都有各自的问题:

手动编写的问题:

  • 工作量大,接口多了容易出错
  • 后端接口变更后,前端需要同步修改
  • 代码重复,每个接口都是相似的 fetch/axios 调用
  • 难以统一管理(错误处理、认证、日志等)

代码生成工具的问题:

  • 需要额外的构建步骤
  • 生成的代码通常很冗长
  • 更新接口需要重新生成和提交大量代码
  • 难以自定义生成逻辑

思考:能不能让前端在运行时动态生成 API 调用函数?

这篇文章分享一下我的思路


核心思路

传统方式

javascript 复制代码
// api/customer.js - 需要手动编写每个函数
export async function getCustomerList(params) {
  const response = await fetch('/api/customer/list', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${getToken()}`
    },
    body: JSON.stringify(params)
  });
  return response.json();
}

// ... 还有几百个类似的函数

主流方式

后端写 Swagger / OpenAPI 文档,或api配置表

前端使用运行脚本根据配置表生成 SDK

生成出类似这样的标准文件:

javascript 复制代码
import { request } from '@/utils/request';

export const Api = {
  getCustomerList(params) {
    return request.post('/api/customer/list', params);
  },
  getCustomerDetail(id) {
    return request.get(`/api/customer/detail/${id}`);
  },
  updateCustomer(id, data) {
    return request.post(`/api/customer/update/${id}`, data);
  }
}

动态生成方式

前提:

  • 后端使用了BFF层
  • 确定的前端url约定,可以通过url推断出对应后端BFF层的API集合
  • 后端提供接口返回 API 元数据(可以根据url返回当前url页面可以调用的API集合)
javascript 复制代码
// 
// 后端接口返回 API 元数据
const apiMetadata = {
  "apis": [
    {
      "method": "getCustomerList",
      "path": "/customer/list",
      "requestMethod": "POST",
      "params": { "status": "String", "name": "String" },
      "returnType": "json"
    },
    {
      "method": "getCustomerDetail",
      "path": "/customer/detail/{id}",
      "requestMethod": "GET",
      "params": { "id": "Long" },
      "returnType": "json"
    },
    {
      "method": "updateCustomer",
      "path": "/customer/update/{id}",
      "requestMethod": "POST",
      "params": { "id": "Long", "data": "Object" },
      "requestBodyParam": "data",
      "returnType": "json"
    }
  ]
};

// 前端根据元数据自动生成所有 API 函数
generateApis(apiMetadata);

// 页面逻辑直接使用,不需要先定义,配置,或手动编写
window.api.getCustomerList({ status: 'active' }, (response) => {
  console.log(response);
});

// 也支持 Promise
const response = await window.api.getCustomerDetail.getPromise(123);

好处:

  1. 前端不需要编写任何 API 调用代码
  2. 后端接口变更,前端自动同步
  3. 可以实现统一的错误处理、认证、日志等Aspect
  4. 后端返回的API元数据甚至可以带一些蜜罐接口,前端代码永远不会调用,但是看起来很好被恶意利用的,而且可以定期变更,前端代码无需修改

因为接口是根据动态返回的元数据自动生成的,为了让前端同学拿到最新的接口文档,可以前端写一个函数,可以通过console调用格式化数据接口文档,类似swagger。另外后端如何定义,识别接口元数据呢,我主要是通过OpenApi的注解识别(一般方法上都已经加过了),只需要单独定义一个注解来标识哪些可以返回给前端。


生成Api部分逻辑实现设计

javascript 复制代码
[业务代码]
       ↓
[uniends.api - 中间件层]
       ↓
  ┌─────────────────────┐
  │  数据分析追踪        │ → 发送行为数据
  │  性能指标采集        │ → 上报到 APM
  │  错误日志            │ → 发送到 Sentry
  │  缓存检查            │ → 查询 Redis 或内存
  │  请求参数加工        │ → 自动补齐 headers
  │  A/B 测试           │ → 路由到不同后端 API
  │  自动生成traceid    │ →  生成唯一请求 ID
  └─────────────────────┘
       ↓
[实际后端 API 调用]
       ↓
[响应处理器]
       ↓
  ┌─────────────────────┐
  │ 成功/失败统计        │ → 上报性能指标
  │ 缓存写入            │
  │ 错误追踪            │
  │ 用户行为分析        │
  └─────────────────────┘
       ↓
[业务回调函数]

根据上方设计可以随时新增Aspect, 页面所有API调用都会经过这些中间件处理。

javascript 复制代码
日志记录       ─┐
埋点追踪       ─┤
缓存           ─┤
错误追踪       ─┤------→ → [后端]
性能监控       ─┤
重试/断路器    ─┤
鉴权          ─┘

实践中的经验

好处

1. 开发效率提升

之前: 每次后端新增接口,前端都要:

  1. 查看接口文档
  2. 手动编写调用函数
  3. 测试
  4. 提交代码

现在: 后端新增接口后,前端直接用,不需要任何额外工作。

2. 接口变更自动同步

后端修改接口url,参数或路径,前端:

  • 之前: 需要找到所有调用的地方,逐个修改或者需要更新接口定义配置表
  • 现在: 自动同步,不需要改任何代码,新增的参数不是必须的可以自动忽略,url变更对前端无感,因为前端是通过固定名称的函数调用。
3. 统一的最佳实践

所有 API 调用自动包含:

  • 认证 token
  • 错误处理
  • 请求日志
  • 性能监控
  • 重试逻辑
  • 超时控制

可以随时新增中间件处理逻辑

4. 更容易的重构

接口具体调用方式为统一封装的,更容易重构

  1. 你的项目中如何管理 API 调用?

    • 手写每个函数?
    • 使用代码生成工具?
    • 还是其他方案?
  2. 你会考虑使用动态生成吗?

    • 如果会,你的顾虑是什么?
    • 如果不会,原因是什么?

总结

以上思路已经有了基本实现,有需要可以交流

相关推荐
Justin3go21 分钟前
HUNT0 上线了——尽早发布,尽早发现
前端·后端·程序员
怕浪猫1 小时前
第一章 JSX 增强特性与函数组件入门
前端·javascript·react.js
铅笔侠_小龙虾1 小时前
Emmet 常用用法指南
前端·vue
钦拆大仁1 小时前
跨站脚本攻击XSS
前端·xss
VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue校园社团管理系统(源码+数据库+文档)
前端·数据库·vue.js·spring boot·后端·课程设计
ChangYan.3 小时前
直接下载源码但是执行npm run compile后报错
前端·npm·node.js
skywalk81634 小时前
在 FreeBSD 上可以使用的虚拟主机(Web‑Hosting)面板
前端·主机·webmin
ohyeah5 小时前
深入理解 React 中的 useRef:不只是获取 DOM 元素
前端·react.js
MoXinXueWEB5 小时前
前端页面获取不到url上参数值
前端
低保和光头哪个先来5 小时前
场景6:对浏览器内核的理解
开发语言·前端·javascript·vue.js·前端框架