☰
TypeGraphQL 与 Microsoft Azure Functions 集成实战:构建 serverless GraphQL 端点
2026/9/28 9:02:49 网站建设 项目流程
  • 后端
  • GraphQL
  • API设计

【免费下载链接】type-graphql

Create GraphQL schema and resolvers with TypeScript, using classes and decorators!

项目地址:https://gitcode.com/gh_mirrors/ty/type-graphql
点击查看免费下载

导读

本指南围绕 TypeGraphQL 官方文档中 "Azure Functions Integration" 一章展开,手把手讲解如何在 Microsoft Azure Functions 的 HTTP Trigger(Http 触发器)中接入 TypeGraphQL:先用buildSchemaSync基于 Resolver 类生成可执行 GraphQL Schema,再把 Schema 交给 Apollo Server,最后通过startServerAndCreateHandler导出为 Azure Function 的默认处理器。读完本文,你将掌握入口函数index.ts、函数绑定配置文件function.json的完整写法,以及适合长期维护的目录组织方式,并能理解emitSchemaFile、container、validate等构建选项在 serverless 场景下的真实作用。

一、集成原理与两个关键步骤

在 Azure Functions 这类 serverless 环境中运行 TypeGraphQL,本质上与常规 Node.js 服务部署没有区别,核心只在于两步:

  1. 生成 GraphQL Schema:把通过@ObjectType、@Resolver、@Query、@Mutation等装饰器声明的类元数据,编译成一个可执行的GraphQLSchema实例;
  2. 把 Schema 交给 Apollo Server:让 Apollo Server 承担查询解析、验证与执行的职责,再把它包装成 Azure Functions 识别的 HTTP 处理器。

该章节是 2.0.0-rc 系列文档的版本化快照,位于 website/versioned_docs/version-2.0.0-rc.2/azure-functions.md,当前仓库主文档对应 docs/azure-functions.md,两者内容一致,可对照阅读。

前置依赖

参照仓库根目录 package.json 的依赖声明(当前仓库版本为2.0.0-rc.4),除 TypeGraphQL 本身外,一个可运行的集成方案通常需要以下包:

依赖用途
reflect-metadata装饰器元数据反射的运行时依赖,TypeGraphQL 必须最先 import
@apollo/serverApollo Server 4/5 核心,承载 Schema 执行(仓库 devDependencies 使用^5.2.0)
@as-integrations/azure-functionsApollo Server 官方 Azure Functions 集成适配器,提供startServerAndCreateHandler
typedi依赖注入容器(仓库 devDependencies 使用^0.10.0),用于container选项
graphqlGraphQL 核心库(TypeGraphQL 的 peerDependency 要求^16.12.0)
class-validator可选的参数校验库(peerDependency>=0.14.3,validate: true时使用)

TypeGraphQL 要求 Node.js 版本>= 20.11.1(见 package.json 的engines字段),Azure Functions 的 Node 运行时需满足该前提。

二、入口函数实现:完整的 index.ts

文档给出了一个可直接套用的 Azure Function 入口实现(即函数根目录下的index.ts),核心思路是在模块顶层同步构建 Schema,因此每个函数实例在加载时只构建一次:

// index.ts import "reflect-metadata"; import path from "path"; import { ApolloServer } from "@apollo/server"; import { startServerAndCreateHandler } from "@as-integrations/azure-functions"; import { buildSchemaSync } from "type-graphql"; import { Container } from "typedi"; import { GraphQLFormattedError } from "graphql"; import { UserResolver } from "YOUR_IMPORT_PATH"; // TypeGraphQL Resolver import { AccountResolver } from "YOUR_IMPORT_PATH"; // TypeGraphQL Resolver // Bundle resolvers to build the schema const schema = buildSchemaSync({ // Include resolvers you'd like to expose to the API // Deployment to Azure functions might fail if // you include too much resolvers (means your app is too big) resolvers: [ UserResolver, AccountResolver, // your other resolvers ], // Only build the GraphQL schema locally // The resulting schema.graphql will be generated to the following path: // Path: /YOUR_PROJECT/src/schema.graphql emitSchemaFile: process.env.NODE_ENV === "local" ? path.resolve("./src/schema.graphql") : false, container: Container, validate: true, }); // Add schema into Apollo Server const server = new ApolloServer({ // include your schema schema, // only allow introspection in non-prod environments introspection: process.env.NODE_ENV !== "production", // you can handle errors in your own styles formatError: (err: GraphQLFormattedError) => err, }); // Start the server(less handler/function) export default startServerAndCreateHandler(server);

下面按代码块逐一拆解关键点。

2.1import "reflect-metadata"必须放在首位

TypeGraphQL 依赖装饰器元数据(emitDecoratorMetadata)驱动类型推断,reflect-metadata必须在任何装饰器使用前完成 polyfill(仓库在tests/functional/errors/metadata-polyfill.ts中也对该依赖做了专项测试保障)。import "reflect-metadata"放在文件第一行是官方推荐的稳妥写法。

2.2buildSchemaSync:同步构建 Schema

与常规服务端常用的buildSchema(异步,见 src/utils/buildSchema.ts)不同,这里使用buildSchemaSync,它在模块加载期间同步完成 Schema 生成(src/utils/buildSchema.ts),无需等待 Promise,因此可以直接把结果赋给模块级常量。从源码结构看,两种 API 内部都会调用SchemaGenerator.generateFromMetadata,区别仅在于是否在构建后同步写出 SDL 文件。

2.3resolvers:显式声明暴露的 Resolver

resolvers数组决定哪些 Resolver 类被注册进 Schema(对应 src/utils/buildSchema.ts 中BuildSchemaOptions.resolvers的NonEmptyArray<Function>类型约束——不允许空数组,源码loadResolvers在空数组时会直接抛错)。

文档在此特别提醒:Azure Functions 部署包过大可能导致部署失败,因此应只包含真正需要对外暴露的 Resolver,把无关 Resolver 挡在 Schema 之外,这既是功能边界,也是控制函数体积的手段。

2.4emitSchemaFile:仅本地生成 SDL 文件

emitSchemaFile: process.env.NODE_ENV === "local" ? path.resolve("./src/schema.graphql") : false,

这是一个典型的"环境区分"写法:

  • 本地开发(NODE_ENV === "local"):把生成的schema.graphql写到src/目录,便于用 GraphQL 工具(如 Playground、IDE 智能提示、代码生成器)消费;
  • 非本地(生产):传false,跳过文件写出,避免在函数运行期做无谓的 IO。

从源码看,emitSchemaFile选项实际支持string | boolean | 配置对象三种形态(src/utils/buildSchema.ts):

  • true:输出到默认路径,即process.cwd()下的schema.graphql(见getEmitSchemaDefinitionFileOptions的默认逻辑,src/utils/buildSchema.ts);
  • string:按给定路径输出;
  • 配置对象:可额外控制打印选项(例如sortedSchema)。

写出 SDL 的底层实现在 src/utils/emitSchemaDefinitionFile.ts:默认会对 Schema 做字典序排序(lexicographicSortSchema)并在文件头部追加一段 "THIS FILE WAS GENERATED BY TYPE-GRAPHQL" 的警告注释,提示该文件为生成产物、不要手改。

2.5container:接入依赖注入容器

container: Container, // 来自 typed-i 的 Container

对应 src/schema/build-context.ts 的container?: ContainerType | ContainerGetter<any>,用于让 Resolver、Service 等类通过 IoC 容器实例化,实现依赖注入。仓库中using-container、using-scoped-container等示例(见 examples/using-container)展示了容器接入的完整姿势;若不传,TypeGraphQL 默认使用无容器模式直接实例化类。

2.6validate: true:启用参数自动校验

validate对应 src/schema/build-context.ts 的ValidateSettings = boolean | ValidatorOptions(src/schema/build-context.ts)。传true表示启用基于class-validator装饰器(@IsEmail、@MinLength等)的入参校验;也可以直接传入一个ValidatorOptions对象做精细化配置。这是文档推荐在生产级 API 中开启的选项。

三、Apollo Server 配置要点

const server = new ApolloServer({ schema, introspection: process.env.NODE_ENV !== "production", formatError: (err: GraphQLFormattedError) => err, });
  • schema:把 TypeGraphQL 构建出的可执行 Schema 注入 Apollo Server;
  • introspection:仅非生产环境开启内省(GraphQL Playground、Apollo Sandbox 依赖它);
  • formatError:按需定制错误输出格式(脱敏、附加上下文、统一结构等),示例中是透传原样返回。

最后export default startServerAndCreateHandler(server)把 Apollo Server 包装成 Azure Functions 的 HTTP 处理器并作为默认导出,函数运行时即会调用该处理器响应请求。

四、function.json:HTTP 触发器的绑定配置

每个 Azure Function 都需要一个同名的function.json配置文件来描述绑定(bindings)。文档给出的 GraphQL 端点配置如下:

// function.json { "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "route": "graphql", "methods": ["get", "post", "options"] }, { "type": "http", "direction": "out", "name": "$return" } ], "scriptFile": "../dist/handler-graphql/index.js" }

逐字段说明:

字段取值含义
authLevel"anonymous"匿名访问即可触发,无需函数级鉴权(业务鉴权可交给 TypeGraphQL 的authChecker/@Authorized机制)
type"httpTrigger"/"http"入站为 HTTP 触发器,出站为 HTTP 响应
direction"in"/"out"绑定方向
name"req"/"$return"入站请求对象名;出站用$return表示直接以返回值作为响应
route"graphql"路由路径,最终端点形如https://<your-app>.azurewebsites.net/api/graphql
methods["get", "post", "options"]允许的 HTTP 方法:GET/POST用于查询执行,OPTIONS用于 CORS 预检
scriptFile"../dist/handler-graphql/index.js"指向编译后的 JS 入口(TypeScript 源码需先编译到dist/,与下文目录结构对应)

注意:scriptFile是相对函数目录的路径,因此当函数放在handlers/handler-graphql/下、编译产物在dist/handler-graphql/时,需要写成"../dist/handler-graphql/index.js"。

五、推荐目录结构:函数与业务代码分离

文档强调:为了代码库的可维护性,不要把 Azure Functions 处理器与 GraphQL Resolver 混放在一起,而是各归其位。推荐的布局如下:

/YOUR_PROJECT /handlers /handler-graphql index.ts function.json /handler-SOME-OTHER-FUNCTION-1 index.ts function.json /handler-SOME-OTHER-FUNCTION-2 index.ts function.json /src /resolvers user.resolver.ts account.resolver.ts /services user.service.ts account.service.ts package.json host.json .eslintrc.js .prettierrc .eslintignore .prettierignore etc etc etc...
  • handlers/:一个子目录对应一个 Azure Function,各自包含index.ts与function.json,职责单一、便于后续新增函数;
  • src/resolvers/、src/services/:GraphQL 业务代码(Resolver、Service、Type 等)独立成层,与 serverless 入口解耦,可被本地服务、测试或其他入口复用;
  • 工程配置(package.json、host.json、ESLint/Prettier 配置等)置于根目录。

这种分层与仓库中 examples 里各个示例的组织风格一致:业务逻辑集中在 resolver/type/service 文件,入口只做组装。

六、serverless 场景的注意事项与参考对照

6.1 Schema 构建成本的取舍

从 src/schema/schema-generator.ts 的实现看,每次generateFromMetadata都会克隆元数据存储、遍历 Resolver 构建类型信息,并在skipCheck为false(默认)时额外执行一次 introspection 查询来校验 Schema 正确性——这是一份不轻的冷启动开销。本文方案把buildSchemaSync放在模块顶层,让同一函数实例只构建一次;但函数实例被回收后的冷启动仍会重建。

如果对冷启动延迟敏感,可以参考仓库中 AWS Lambda 集成文档(docs/aws-lambda.md)给出的缓存模式:用模块级变量配合??=条件赋值,把 Schema 与 Server 缓存到实例生命周期内,避免每次请求重复构建:

let cachedSchema: GraphQLSchema | null = null; let cachedServer: ApolloServer | null = null; export const handler = async (event, context, callback) => { cachedSchema ??= await buildSchema({ resolvers: [RecipeResolver] }); cachedServer ??= new ApolloServer({ schema: cachedSchema }); // ... };

两种方案的取舍:文档版代码更简洁、结构更直观;缓存版在多次冷启动场景下可省去重复构建。可按团队偏好选择,但无论哪种,Schema 构建都只应发生一次。

6.2 部署包大小

文档明确提醒:"Deployment to Azure functions might fail if you include too much resolvers (means your app is too big)"。Azure Functions(特别是消费计划)对部署包大小有限制,因此:

  • resolvers数组只注册真正对外暴露的 Resolver;
  • 利用emitSchemaFile的本地生成能力把schema.graphql纳入版本管理/CI 检查,及时发现类型错误;
  • 必要时按领域拆分多个函数,各函数只携带自己需要的 Resolver 集合,配合上面的多handlers目录结构落地。

6.3 本地开发验证

本地运行 Azure Functions 工具时,NODE_ENV=local会让emitSchemaFile生效,把最新 Schema 写入src/schema.graphql;之后既可用 Apollo Sandbox / GraphQL Playground 直连本地端点调试,也可用该 SDL 文件做客户端代码生成。生产环境传false则完全跳过写盘,避免无谓 IO。

七、小结

把 TypeGraphQL 接到 Azure Functions 上,只需三步:用buildSchemaSync基于 Resolver 生成 Schema → 注入 Apollo Server → 用startServerAndCreateHandler导出为函数处理器,再配一份声明了httpTrigger绑定与编译产物入口的function.json。官方推荐把函数处理器与业务 Resolver 分层存放,并借助emitSchemaFile仅在本地产出 SDL、借助container/validate开启依赖注入与入参校验。以上配置细节与实现依据均可在仓库 docs/azure-functions.md、src/utils/buildSchema.ts 与 src/schema/build-context.ts 中进一步查阅验证。

  • 后端
  • GraphQL
  • API设计

【免费下载链接】type-graphql

Create GraphQL schema and resolvers with TypeScript, using classes and decorators!

项目地址:https://gitcode.com/gh_mirrors/ty/type-graphql
点击查看免费下载
上一篇:Visual Prompt Tuning (VPT)完全解析:ECCV 2022视觉迁移学习新范式
下一篇:微信多设备登录方案:启用平板模式实现多设备同步

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询