TypeGraphQL 解析器(Resolvers)详解:构建强大的GraphQL API
type-graphql 项目地址: https://gitcode.com/gh_mirrors/typ/type-graphql
TypeGraphQL 是一个基于 TypeScript 的 GraphQL 框架,它通过装饰器和类语法简化了 GraphQL 模式的创建过程。本文将深入探讨 TypeGraphQL 中的解析器(Resolvers)概念,帮助开发者高效构建 GraphQL API。
解析器基础概念
在 GraphQL 中,解析器是负责获取和返回数据的函数。TypeGraphQL 通过类和方法装饰器的方式,让解析器的创建变得直观且类型安全,类似于传统 REST 框架中的控制器模式。
查询(Query)和变更(Mutation)解析器
创建解析器类
首先创建一个类并用 @Resolver()
装饰器标记:
@Resolver()
class RecipeResolver {}
这个类可以包含业务逻辑,也可以注入依赖项(如服务或存储库),确保整个应用中只有一个实例。
基本查询示例
下面是一个返回所有食谱的查询示例:
@Resolver()
class RecipeResolver {
private recipesCollection: Recipe[] = [];
@Query(returns => [Recipe])
async recipes() {
return await this.recipesCollection;
}
}
注意:
- 使用
@Query
装饰器标记方法为 GraphQL 查询 - 通过
returns => [Recipe]
指定返回类型为 Recipe 数组
处理参数
GraphQL 查询通常需要参数,TypeGraphQL 提供两种参数定义方式:
1. 内联参数(使用 @Arg
装饰器)
@Query(returns => [Recipe])
async recipes(
@Arg("servings", { defaultValue: 2 }) servings: number,
@Arg("title", { nullable: true }) title?: string,
): Promise<Recipe[]> {
// 实现逻辑
}
2. 参数类(使用 @ArgsType
装饰器)
当参数较多时,推荐使用参数类:
@ArgsType()
class GetRecipesArgs {
@Field(type => Int, { defaultValue: 0 })
@Min(0)
skip: number;
@Field(type => Int)
@Min(1)
@Max(50)
take = 25;
@Field({ nullable: true })
title?: string;
}
然后在解析器中使用:
@Query(returns => [Recipe])
async recipes(@Args() { title, skip, take }: GetRecipesArgs) {
// 实现分页和过滤逻辑
}
变更(Mutation)解析器
变更解析器与查询类似,但通常使用输入类型(Input Types):
@InputType()
class AddRecipeInput implements Partial<Recipe> {
@Field()
title: string;
@Field({ nullable: true })
description?: string;
}
@Resolver()
class RecipeResolver {
@Mutation()
addRecipe(@Arg("data") newRecipeData: AddRecipeInput): Recipe {
// 实现添加逻辑
}
}
字段解析器(Field Resolvers)
字段解析器用于解决对象类型中的复杂字段,例如关联数据或计算字段。
基本字段解析器
@Resolver(of => Recipe)
class RecipeResolver implements ResolverInterface<Recipe> {
@FieldResolver()
averageRating(@Root() recipe: Recipe) {
const sum = recipe.ratings.reduce((a, b) => a + b, 0);
return recipe.ratings.length ? sum / recipe.ratings.length : null;
}
}
关键点:
@Resolver(of => Recipe)
指定解析的类@FieldResolver()
标记为字段解析器@Root()
获取父对象ResolverInterface<Recipe>
提供类型安全
复杂字段解析器
对于需要依赖注入的复杂场景:
@Resolver(of => Recipe)
class RecipeResolver {
constructor(
private readonly userRepository: Repository<User>,
) {}
@FieldResolver()
async author(@Root() recipe: Recipe) {
return await this.userRepository.findById(recipe.userId);
}
}
高级技巧
- 内联字段解析器:简单计算字段可以直接在对象类型中定义
- 默认值:通过
defaultValue
选项或属性初始化器设置 - 验证:结合 class-validator 进行参数验证
- 上下文访问:使用
@Ctx()
装饰器获取上下文信息
最佳实践
- 保持解析器精简,将复杂逻辑委托给服务层
- 使用参数类处理多个参数
- 为计算密集型字段使用字段解析器
- 充分利用 TypeScript 的类型系统确保类型安全
- 考虑性能,特别是对于嵌套字段解析器
通过 TypeGraphQL 的解析器系统,开发者可以构建结构清晰、类型安全的 GraphQL API,同时保持代码的可维护性和可测试性。无论是简单的 CRUD 操作还是复杂的业务逻辑,TypeGraphQL 都提供了优雅的解决方案。
type-graphql 项目地址: https://gitcode.com/gh_mirrors/typ/type-graphql
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考