统一范式:中后台Admin项目标准化API分层开发方案(Vue/React通用)
前言
中后台Admin系统开发,说到底,API层是所有业务的地基。用户管理、权限配置、字典维护、日志审计、文件上传……几乎没有一个后台功能能绕开前后端的数据交互。
一个很现实的问题是:不少团队在API层开发上长期“各自为战”——接口调用方式五花八门,数据缓存没有统一方案,组件内外的调用逻辑不统一,TS类型全靠手写,连Vue和React两套技术栈的规范也对不上。后果是什么?新人上手速度慢,代码冗余度高,隐藏Bug频出,迭代效率自然上不去。
为了解决这些痛点,我们基于Axios(底层请求库)、TanStack Query(原React Query/Vue Query,异步状态管理)和TypeScript强类型约束,配合gRPC后端接口体系,设计了一套三层分层API架构。这套架构同时适配Vue和React,把网络请求、缓存管理、业务逻辑、UI渲染的职责彻底分开,做到类型全覆盖、调用方式标准化、业务开发轻量化。下面就来完整拆解这套框架的设计理念与落地规范,帮助团队快速提升中后台开发效率。
一、技术选型底层逻辑
这套API框架,核心依靠三大主流技术,专门针对Admin后台的特性做了适配。
1.1 TanStack Query:现代异步状态管理担当
它负责接管异步数据状态和缓存管理,底层请求载体依旧是Axios。它的出现,替代了过去那种手动封装axios、再用Zustand或Pinia维护异步数据的“老黄历”方案。作为现代化的异步状态管理工具,它原生支持自动缓存、窗口聚焦刷新、请求防抖、垃圾回收、分页/无限加载、离线请求这些后台高频能力,开发者再也不用去手写缓存管理、加载状态、失败重试这些繁杂的逻辑。最关键的是,它零额外第三方依赖,完美跨框架适配Vue/React/Svelte/Angular全技术栈,可以说是中后台项目里异步数据管理的最优选择,极大简化了数据请求与状态同步。
1.2 TypeScript:全层级的铠甲
TypeScript强类型约束贯穿整个API层级——从自动生成的后端接口类型,到请求参数、响应数据、分页结构体,全程实现类型校验与智能提示。这能从根源上避免参数传错、字段拼写错误等问题,代码可维护性自然就上去了,尤其适合大型企业级Admin系统的开发,确保接口类型安全与代码健壮性。
1.3 gRPC+Protobuf:接口同步的“金标准”
后端统一使用gRPC定义接口,通过protoc-gen-typescript-http插件自动生成前端TS类型与请求客户端。前后端类型不同步、接口文档滞后——这些经典问题,在它面前迎刃而解,接口类型一键同步不再是梦,显著提升前后端协作效率。
二、整体架构设计:三层分层架构
这套方案没有采用粗放式的直接请求模式,而是把API层从上到下拆成业务Hook层、Service服务层、自动生成层三层结构。核心原则就是单向依赖、职责分离、环境隔离:上层依赖下层,禁止反向调用;每一层只干好自己的活,互不越界。这套结构在Vue和React项目中完全一致,唯一的区别是Hooks层需要适配对应框架的API,实现了真正的跨栈统一。
2.1 架构总览
UI层(Vue组件/React组件)
↓ 依赖
Hook层(Composables/Hooks)→ 封装TanStack Query,面向业务,提供两种调用模式
↓ 依赖
Service服务层 → 纯异步函数,封装接口客户端,处理参数适配
↓ 依赖
Generated自动生成层 → Protobuf自动生成类型+客户端,禁止手动修改
2.2 核心设计原则
- 单向依赖:UI→Hook→Service→Generated,下层绝对不能直接调上层的功能。
- 职责单一:每层只做好自己的核心工作,剥离掉所有的冗余耦合逻辑。
- 环境隔离:区分组件运行环境、全局Store/路由守卫等非组件环境,提供差异化的调用方案。
- 双栈统一:目录结构、命名规范、新增模块流程,Vue和React完全对齐,降低跨技术栈的学习成本。
三、分层详解(核心)
3.1 第一层:Generated 自动生成层(底层)
3.1.1 定位
整个API架构的数据基础。由Protobuf文件自动生成,全程禁止手动编辑——所有改动都得先同步后端protobuf文件,然后重新编译生成。
3.1.2 核心能力
- 全量接口TS类型:包含请求体、响应体、枚举、实体类(比如用户、角色、字典等实体)。
- Service客户端工厂函数:针对后端的每一个gRPC服务,生成对应的客户端创建方法。
- 统一命名规则:采用
{服务标识}v1_{消息名称}的格式,能直观区分权限、用户、认证、字典等业务模块。
3.1.3 适用场景
它只是一个底层依赖,供Service层导入使用。业务开发者正常情况下不需要直接去碰这个目录的代码。
3.2 第二层:Service 服务层(中间层)
3.2.1 定位
架构里的适配层,承上启下。它的任务是把自动生成的客户端封装起来,剥离掉框架特性,输出纯异步函数——不带任何Vue/React框架的依赖,可以在任意JS/TS环境里运行。
3.2.2 核心职责
- 单例管理:用延迟初始化模式缓存每个服务的客户端实例,避免重复创建浪费资源。
- 参数适配:统一封装分页结构体
PaginationQuery,自动完成请求参数格式化。 - 接口封装:按照固定的命名规范,封装列表查询、详情、新增、编辑、删除等基础接口。
- 原始异常透传:不做全局异常捕获,把错误原样向上抛,交给上层的Hook层统一处理。
3.2.3 统一开发规范
所有的Service文件都遵循统一模板,命名规则是固定的:
- 客户端获取函数:
getXxxService()。 - 接口函数:列表
listXxx、详情getXxx、新增createXxx、更新updateXxx、删除deleteXxx。
3.3 第三层:Hook/Composables 业务层(顶层)
3.3.1 定位
这是面向业务开发者的最终调用入口,也是日常开发中使用最多的层级。它基于TanStack Query包装Service层的异步函数,适配双技术栈:Vue项目叫Composables,React项目叫Hooks。
3.3.2 双调用模式(核心亮点)
为了覆盖后台项目复杂的运行环境,每一个接口都提供两种调用方式:
- useXxx(Hook/组合式函数):仅用于组件内部,依托TanStack Query自带的加载状态、缓存、防抖、状态管理能力,拿来就用。
- fetchXxx(纯Promise函数):没有框架上下文依赖,专门用于Zustand/Pinia全局状态、路由守卫、工具函数、异步任务等非组件环境。
3.3.3 附加能力
- 通用枚举工具:内置启用状态、业务状态、HTTP请求方法等全局映射函数,快速实现状态文字/颜色转换。
- 缓存精细化配置:支持自定义缓存时长、失败重试、缓存失效,能精准适配增删改查不同接口的业务需求。
- 统一全局异常:封装全局请求错误拦截,自动处理401 Token过期、403权限不足等后台通用异常。
四、目录结构规范(Vue/React对齐)
为了让团队开发习惯统一,两套技术栈采用完全一致的目录结构,只有顶层组合式函数目录名称有所区分:Vue用composables,React用hooks。
src/api/
├── index.ts # API模块统一导出总入口
├── generated/ # 自动生成层(勿手动修改)
│ └── admin/service/v1/
│ └── index.ts # 类型+客户端工厂集合
├── service/ # Service服务层(双栈完全一致)
│ ├── auth.ts / user.ts / role.ts # 按后端服务拆分文件
│ └── index.ts # 服务统一导出
└── composables/hooks/ # 业务Hook层(差异化适配)
├── shared.ts # 全局通用枚举工具
├── auth.ts / user.ts # 与service文件一一对应
└── index.ts # Hook统一导出
目录拆分严格按照后台业务模块划分:认证授权、用户租户、组织架构、权限管理、系统配置、审计日志、站内消息,结构非常清晰,新人也能快速找到对应的接口,降低上手成本。
五、业务场景使用指南
我们以最经典的用户管理模块为例,来说说不同场景下该怎么调用。
5.1 组件内部调用(推荐useXxx)
在页面组件、弹窗组件这些场景下,直接用useXxx。它能自动接管loading、error、缓存状态,不用再手动定义变量去维护加载状态。下面用Vue举例,React的用法逻辑完全一样:
5.2 全局Store调用(推荐fetchXxx)
在Zustand/Pinia状态库里,用没有依赖的fetch函数,可以避免Hook上下文报错:
import { create } from 'zustand';
import { fetchListUsers } from '@/api/hooks/user';export const useUserStore = create((set) => ({
userList: [],
// 加载用户列表
loadUserList: async (query) => {
const res = await fetchListUsers(query);
set({ userList: res.items });
}
}));
5.3 路由守卫/工具函数调用
像动态生成路由、权限校验这类前置逻辑,同样用fetch系列函数:
import { fetchMyPermissionCode } from '@/api/composables/admin-portal';// 校验当前用户路由权限
export async function checkRoutePermission(route: string) {
const permissionList = await fetchMyPermissionCode();
return permissionList.includes(route);
}
5.4 标准化增删改操作
框架内置了updateMask自动生成能力,更新接口时只需要传递变更的字段,减少了多余的传参:
// 更新用户信息
const { mutateAsync } = useUpdateUser();
await mutateAsync({
id: 1,
values: { name: "更新后的用户名" } // 仅传递变更字段即可
});
六、新增业务模块标准化流程
当后端新增一个gRPC业务服务,比如消息通知服务(NotificationService),开发者的操作流程非常标准化,4步走完,没有自定义开发成本:
- 同步生成底层代码:拉取最新的protobuf文件,执行编译命令,更新generated目录下的类型与客户端。
- 编写Service层:新建一个
notification.ts,初始化客户端单例,封装基础的CRUD异步函数。 - 编写Hook层:对应创建Hook文件,封装use系列接口与fetch系列接口,配置好缓存策略。
- 统一导出注册:分别在service、composables/hooks的index.ts中导出当前模块,全局生效。
七、全局TanStack Query配置(后台专属)
考虑到Admin系统数据更新频率低、静态数据多的特点,我们统一全局默认配置,所有接口共享:
- staleTime:60s。60秒内重复请求直接读缓存,减少无效网络请求。
- retry:false。接口请求失败不自动重试,避免重复请求干扰后台数据。
- refetchOnWindowFocus:false。窗口聚焦时不自动刷新。
- refetchOnReconnect:false。网络重连时不自动刷新。
八、开发红线与最佳实践
8.1 开发红线(禁止操作)
- 禁止手动修改generated目录里的任何代码。
- 禁止在Service层使用框架Hook或组合式函数,必须保持纯函数特性。
- 禁止在非组件环境直接调用useXxx系列接口。
- 更新接口禁止传递全量字段,必须只传递变更字段,依托updateMask优化请求。
8.2 最佳实践
- 查询类接口开启缓存,增删改类接口关闭缓存,平衡性能与数据实时性。
- 数据变更后,通过
invalidateQueries主动失效对应的缓存,自动刷新页面数据。 - 所有列表查询统一使用
PaginationQuery结构体,统一参数格式。 - 异常分层处理:底层Service透传错误,Hook层处理业务提示,全局统一兜底异常。
九、总结
这套三层分层API开发框架,实际上把传统Admin项目里那些烦人的痛点都系统地解决了——接口调用混乱、双技术栈规范不统一、缓存管理麻烦、类型不安全,等等。
从开发效率来看:标准化的目录结构、固定的新增模块流程、开箱即用的CRUD接口、内置缓存与状态管理——至少能减少70%以上的重复请求逻辑编写工作,让团队聚焦业务本身。
从维护性来看:强TypeScript类型约束、单向依赖架构、统一编码规范,让团队协作和后续迭代的成本都降下来了,长期维护更轻松。
从适配性来看:完美兼容Vue/React双技术栈,能覆盖组件、Store、路由守卫、工具函数等所有后台运行场景,可以说是全面覆盖了中后台的所有业务需求,真正实现技术栈无关的标准化开发。
后续所有的Admin类新项目,包括存量项目的迭代,都推荐统一采用这套API开发范式,真正实现团队开发的标准化、轻量化和高效化。
附录:项目地址与演示信息
这套分层API架构已经完整落地在 GoWind Admin(风行) 全栈中后台脚手架。脚手架依托Kratos微服务后端,同步提供Vue3 Vben、Vue3 Element Plus、React Antd三大前端版本,支持单体/微服务双模式部署,开箱即用。
- GitHub 仓库:github.com/tx7do/go-wi…
- Gitee 仓库:gitee.com/tx7do/go-wi…
- 在线演示地址:demo.admin.gowind.cloud
- 默认登录账号密码:admin / admin
