NestJS GraphQL Federation Schema-First 实战:users-application 子服务完整实现解析

发布时间:2026/9/30 2:01:32

NestJS GraphQL Federation Schema-First 实战:users-application 子服务完整实现解析 后端Web框架【免费下载链接】nestA progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 项目地址https://gitcode.com/GitHub_Trending/ne/nest点击查看免费下载本指南围绕 NestJS 仓库中 GraphQL FederationSchema-First 模式示例的 users-application 子服务展开系统讲解如何用nestjs/graphql与ApolloFederationDriver构建一个可被联邦网关合并的独立子服务从 Schema 定义、key实体标记、ResolveReference引用解析到模块装配与启动运行。读完你既能照抄一份可运行的联邦子服务骨架也能理解其在多服务架构中的角色边界。一、示例在仓库中的位置与整体结构本示例位于 sample/32-graphql-federation-schema-first/users-application 目录是 GraphQL FederationSchema-First示例套件的用户子服务部分。整个 32 号示例由三个应用组成gatewayApollo Gateway负责合并各子服务的 Schema 并对外统一提供查询入口users-application本文主角提供User实体与getUser查询posts-application另一子服务通过联邦引用reference解析User的关联数据。users-application 的文件布局如下users-application/ ├── src/ │ ├── app.module.ts │ ├── main.ts │ └── users/ │ ├── models/user.model.ts │ ├── users.graphql │ ├── users.module.ts │ ├── users.resolver.ts │ ├── users.resolver.spec.ts │ ├── users.service.ts │ └── users.service.spec.ts ├── nest-cli.json ├── package.json ├── tsconfig.json └── vitest.config.mts子服务本身是标准 NestJS 应用入口、根模块、业务模块一应俱全唯一特别之处在于根模块中接入的是GraphQLModule.forRoot且驱动为ApolloFederationDriver见 users.module.ts。二、依赖与脚本搭建联邦子服务需要什么package.json 是本子服务的依赖清单其中与联邦直接相关的核心依赖为nestjs/graphql14.xNestJS GraphQL 集成层nestjs/apollo14.x提供ApolloFederationDriver与ApolloFederationDriverConfigapollo/subgraph2.15.xApollo 子服务构建工具apollo/gateway2.14.x网关依赖此示例中 gateway 与子服务共用同一份依赖约定graphql17.x与graphql-tools9.xSchema 解析与工具库reflect-metadataNest 依赖注入与装饰器元数据所需。项目脚本与 NestJS 标准模板一致但测试统一走 Vitest# 安装依赖 $ npm install # 开发模式 $ npm run start # 监听模式 $ npm run start:dev # 生产模式先构建再启动 $ npm run start:prod # 单元测试Vitest $ npm run testtype: module表明该子服务以 ESM 方式运行这也是main.ts中导入路径带.js后缀的原因见下文。vitest.config.mts将测试范围限定为src/**/*.spec.ts并开启全局断言。三、模块装配ApolloFederationDriver 的接入方式3.1 根模块app.module.ts 只是简单导入UsersModule不注册任何控制器或全局 providerimport { Module } from nestjs/common; import { UsersModule } from ./users/users.module.js; Module({ imports: [UsersModule], controllers: [], providers: [], }) export class AppModule {}3.2 业务模块GraphQL 配置真正的联邦配置在 users.module.tsimport { ApolloFederationDriver, ApolloFederationDriverConfig, } from nestjs/apollo; import { Module } from nestjs/common; import { GraphQLModule } from nestjs/graphql; import { UsersResolver } from ./users.resolver.js; import { UsersService } from ./users.service.js; Module({ providers: [UsersResolver, UsersService], imports: [ GraphQLModule.forRootApolloFederationDriverConfig({ driver: ApolloFederationDriver, typePaths: [**/*.graphql], }), ], }) export class UsersModule {}关键点driver: ApolloFederationDriver将 GraphQL 执行引擎切换为 Apollo Federation 专用驱动子服务因此会暴露联邦必需的_serviceSDL 查询与_entities实体解析端点typePaths: [**/*.graphql]是 Schema-First 的核心配置NestJS 会按该 glob 自动扫描并合并所有.graphql文件作为 SDL。这正是Schema-First与 Code-First装饰器直接生成 Schema的区别所在。四、Schema-First 的 Schema 定义联邦实体声明users.graphql 是子服务对外发布的 SDLtype User key(fields: id) { id: ID! name: String! } extend type Query { getUser(id: ID!): User }逐行解读key(fields: id)联邦规范的核心指令声明User类型在本子服务中的主键为id。网关将依据该键把不同子服务中同类型的实体合并为一个完整对象type User定义了实体字段idID!非空与nameString!非空extend type Query子服务不拥有全局Query的完整定义因此用extend把自己的查询getUser(id: ID!): User追加到合并后的根类型上。Code-First 等价实现对照本示例同时提供了 Code-First 的联邦版本见 sample/31-graphql-federation-code-first。在 Schema-First 中key写在.graphql文件里而 Code-First 则用装饰器表达user.model.ts 展示了如何在 NestJS 中把 SDL 映射为 TypeScript 类import { Directive, Field, ID, ObjectType } from nestjs/graphql; ObjectType() Directive(key(fields: id)) export class User { Field((type) ID) id: number; Field() name: string; }Directive(key(fields: id))与.graphql文件中的key(fields: id)一一对应说明无论哪种模式联邦语义键与引用解析都是通过同一套指令体系表达的。该模型文件在本 Schema-First 示例中主要供 Resolver 与 Service 引用类型Schema 本体仍以 SDL 为准。五、Resolver普通查询与联邦引用解析users.resolver.ts 是子服务的解析层同时承担两类职责import { Args, ID, Query, Resolver, ResolveReference } from nestjs/graphql; import { UsersService } from ./users.service.js; Resolver(User) export class UsersResolver { constructor(private usersService: UsersService) {} Query() getUser(Args({ name: id, type: () ID }) id: number) { return this.usersService.findById(id); } ResolveReference() resolveReference(reference: { __typename: string; id: number }) { return this.usersService.findById(reference.id); } }5.1 普通查询getUserQuery()对应 SDL 中的getUser(id: ID!): User参数id声明为ID类型。Resolver(User)将 Resolver 与User类型绑定使方法返回值具备联邦实体语义。5.2 联邦引用解析resolveReferenceResolveReference()是联邦子服务的关键钩子当网关跨子服务合并实体时会向本子服务发送一个引用对象包含__typename与主键字段id本方法据此加载并返回完整实体。这里接收的reference结构为{ __typename: string; id: number }与联邦规范中_entities解析器收到的参数一致。可以推断网关在posts-application中遇到对User的引用例如帖子关联作者时正是调用这里的方法把id解析回{ id, name }完整对象——这是联邦单实体、多子服务分工的数据流核心。六、Service数据存取层users.service.ts 使用内存数组模拟数据源便于示例零依赖运行import { Injectable } from nestjs/common; Injectable() export class UsersService { private users [ { id: 1, name: John Doe }, { id: 2, name: Richard Roe }, ]; findById(id: number) { return this.users.find((user) user.id Number(id)); } }findById同时服务于getUser查询与resolveReference引用解析一条数据路径两处复用Number(id)将字符串/数字形式的ID统一转换为数字比较规避 GraphQLID标量序列化带来的类型差异生产环境中该内存数组可替换为 TypeORM、Prisma 或远程 APIResolver/Service 的分层使替换成本极低。七、启动入口与运行验证main.ts 与普通 NestJS 应用无异import { NestFactory } from nestjs/core; import { AppModule } from ./app.module.js; async function bootstrap() { const app await NestFactory.create(AppModule); await app.listen(3000); } await bootstrap();注意两点顶层 await因package.json声明type: module文件采用 ESM 语法bootstrap()直接以顶层await执行无需包裹在void bootstrap()中导入后缀.jsESM 下 TypeScript 编译产物为.js导入路径必须显式写.js才能在 Node 侧正确解析。运行$ cd sample/32-graphql-federation-schema-first/users-application $ npm install $ npm run start启动后服务监听 3000 端口。若配合同一示例中的gateway应用默认端口 4000一起启动网关会通过子服务的联邦端点拉取 SDL 并合并 Schema直接访问子服务的 GraphQL 端点可用如下查询验证getUserquery { getUser(id: 1) { id name } }预期返回{ data: { getUser: { id: 1, name: John Doe } } }。八、测试Resolver 与 Service 的单元验证仓库为子服务配备了两份 Vitest 单元测试配置见 vitest.config.mts将include限定为src/**/*.spec.tsusers.resolver.spec.tsmockUsersService后验证getUser与resolveReference的返回users.service.spec.ts验证findById的数据查找逻辑。运行测试$ npm run test # vitest run $ npm run test:watch # 监听模式 $ npm run test:cov # 覆盖率九、小结Schema-First 联邦子服务的四要素综合以上源码一个可被联邦网关合并的 NestJS 子服务由四要素构成驱动接入GraphQLModule.forRoot使用ApolloFederationDriverusers.module.tsSDL 声明.graphql文件定义实体并以key(fields: id)标注主键用extend type Query追加查询users.graphql引用解析ResolveReference()方法根据网关下发的引用对象还原完整实体users.resolver.ts数据服务将查询与解析统一委托给 Service 层保持数据源可替换users.service.ts。如需对比装饰器风格的联邦写法可参考同仓库的 sample/31-graphql-federation-code-first若要查看网关如何合并本子服务的 Schema参见 32-graphql-federation-schema-first/gateway 目录及其 README.md。赞分享后端Web框架【免费下载链接】nestA progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 项目地址https://gitcode.com/GitHub_Trending/ne/nest点击查看免费下载相关推荐YouTube.js 的 JsMatchers基于 ESTree AST 的 n/sig 解密函数提取匹配器深度解析YouTube.js 的 JsMatchers基于 ESTree AST 的 n/sig 解密函数提取匹配器深度解析 导读 JsMatchers 是 YouT后端Web框架使用 Java 与 graphql-java 构建 GraphQL 服务器从 schema-first 到 code-first 的完整指南使用 Java 与 graphql java 构建 GraphQL 服务器从 schema first 到 code first 的完整指南 本指南以 howGraphQL Java 实战从 Schema-First 到 Code-First用 graphql-spqr 从业务代码直接生成 SchemaGraphQL Java 实战从 Schema First 到 Code First用 graphql spqr 从业务代码直接生成 Schema 本文围绕上一篇Netmiko自动检测黑科技智能识别网络设备类型的完整教程下一篇打造专属音乐云洛雪音乐数据同步服务全攻略创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/30 2:01:32

旧Mac免费升级指南:用OpenCore Legacy Patcher装上新款macOS

旧Mac免费升级指南:用OpenCore Legacy Patcher装上新款macOS 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 打开"软件更新"却找不到任…

2026/9/30 2:01:32

函数

一、引入 存在的问题: 1. 代码冗余,代码量太大 2. 维护性差,复制容易,修改难 如何解决此问题???? 1. 对反复的代码只写一次,并对它起个名字 2. 想使用次功能代码时&#…

2026/9/30 3:11:35

嵌入式开发AI agent环境搭建(arm-none-eabi / SDCC / OpenOCD)

推荐架构:Windows VSCode AI Agent,工具链覆盖 arm-none-eabi-gcc、SDCC、OpenOCD。 推荐架构 角色 工具 用途 编辑器 VSCode C/C 编辑、终端、任务管理 编译器 arm-none-eabi-gcc ARM Cortex-M / RTOS 项目 编译器 SDCC 51、STC、部分 8051 兼容 MCU …

2026/9/30 3:11:35

WiFi大师专业版4.0.5独立部署与流量主广告接入实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 3:11:35

从二进制数1开始:进制转换、位运算与工程实战复盘

1. 从“二进制数1”说起:为什么每日一题要从进制开始刷最早在牛客的每日一题列表里看到《二进制数1》这个标题时,我其实有点不以为然。心想二进制嘛,十进制转二进制、二进制转十进制,大一C语言课早就学过的东西,还需要…

2026/9/30 3:11:35

Cloud Functions WebSocket部署失败排查与迁移指南

如果你在一个Python项目里同时看到OperationError: code3的红色输出,和requirements.txt里躺着websockets这一行,那大概率已经踩到了Google Cloud Functions和长连接之间最深的那个坑。我最初是在一个实时聊天服务里遇到这个问题的:本地用Pyt…

2026/9/30 3:06:35

Spring Boot+Vue 3家具商城实战:数据库设计、库存扣减与Docker部署

1. 家具商城这个选题,难的不是商城而是家具先说个有意思的现象。每年到毕设季,或者想自己做点东西充实简历的时候,"商城系统"永远是出现频率最高的题目。书城、电商城、服装城、二手交易平台,改个名字就是一套新的。但如…

2026/9/29 11:07:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/29 21:48:03

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 7:00:49

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 0:01:22

MATLAB+Yalmip+CPLEX实战:综合能源系统优化调度全流程解析

做综合能源系统优化调度这活儿,最痛苦的不是建模本身,而是模型写完之后不知道该怎么求解。看论文里轻飘飘一句“采用Yalmip调用CPLEX求解”,自己上手时却往往卡在环境配置、变量声明、约束写法和求解状态判读上,一耗就是两三天。这…

2026/9/30 0:01:22

I3C比I2C快10倍?RK3576实战:速率、DTS配置与混合总线避坑指南

I3C 比 I2C 快 10 倍?这句话在嵌入式群里传了很久,每次都能吵出一堆截图。前段时间我正好在 RK3576 上调板级 I3C 接口,从控制器寄存器一路摸到 Linux DTS 配置,踩了不少坑,也把这笔速度账彻底算明白了。本文就用 RK35…

2026/9/30 0:01:22

字符串转对象:JSON.parse、new Function与URLSearchParams

“字符串转对象”这几个字,我在技术群里见过的问法至少有十几种:有人拿着一串{a:1,b:2}说 JSON.parse 直接报错,有人要从 URL 里抠出参数,还有人只是想把abc变成能挂属性的东西。js 这门语言里,字符串和对象之间的转换…

2026/9/29 3:53:39

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/29 9:46:12

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/29 6:36:14

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑