GraphQL 中的嵌套字段解析器
Nested field resolvers in GraphQL
目标是使用 NestJS 通过代码优先方法实现 GraphQL 模式。
假设我的 GraphQL 模式中有一个 Pet
类型,其中包含两个字段,name
和 age
。如果这两条信息来自不同的真实来源(我并不总是想同时获取两者),我可以为每个字段实现一个 PetResolver
class 解析器:
@Resolver(() => Pet)
export class PetResolver {
@Query(() => Pet)
pet(): Pet {
return {};
}
@ResolveField()
name(): Promise<string> {
return Promise.resolve('Spot');
}
@ResolveField(() => Int)
age(): Promise<number> {
return Promise.resolve(2);
}
}
可以这样使用:
query GetPet {
pet {
name
}
}
这行得通并且可以确保每个字段的值仅在请求时获取,但是如果我想在我的 User
类型上有一个 pet
字段,我可以像这样查询:
query GetUserWithPet {
currentUser {
email
pet {
name
}
}
}
应用相同的原理,我可以创建一个 UserResolver class,如下所示:
@Resolver(() => User)
export class UserResolver {
@Query(() => User)
@UseGuards(AuthCognitoGuard)
currentUser(@CurrentUser() user: IdTokenPayload): User {
return {
id: user.sub,
email: user.email,
};
}
@ResolveField()
pet(@Parent() user: User): Promise<Pet> {
return petService.getPetForUserId(user.id);
}
}
但是 PetService
实现如果只想获取相关数据就必须知道请求了哪些字段。
A) 有没有办法在 UserResolver
中使用 PetResolver
来利用单独的字段解析逻辑?
B) 如果不是,使用 NestJS 代码优先约定确定查询中请求了哪些字段的最佳方法是什么?
C) 这是考虑 GraphQL 查询的“错误”方式吗?最佳实践是否要求我保留单独的解析器并使用如下查询:
query GetUserWithPet {
currentUser {
email
}
pet {
name
}
}
用户应该包含一些 petIds
[数组] 值(内部,数据库存储 field/column)...
... 可以解析 pets: [Pet]
prop/relation - Pet
列表 ...
... 就像 starshipIDs
在 https://graphql.org/learn/execution/
中解释的那样
注意:宠物服务被询问使用宠物id的记录。
...但当然 pet 可以包含一些 ownerId
(仅或显式可见,数据库存储 field/column)使得解析 owner: User
prop [reverse] 关系成为可能 - 这你可以这样:
query PetWithOwner {
pet (id: "someID") {
id
name
owner {
id
email
# more pets?
pets {
id
name
# you can loop it ;)
owner {
id
email
pet.owner
字段解析器只能 return { id: ownerId }
对象(部分响应)...服务器将尝试解析 'missing'(查询需要)email
道具使用 User
(owner
是 User
类型)类型解析器,将 id 作为参数传递(check/console.log parent
和 args
解析器参数)。您不必在 pet.owner
字段解析器中[相同] 'manually'。
查询必填字段...
... [选择集] 可以从 info
对象中读取 - 第 4 个解析器 arg - 阅读 docs/tutorial 了解详细信息
目标是使用 NestJS 通过代码优先方法实现 GraphQL 模式。
假设我的 GraphQL 模式中有一个 Pet
类型,其中包含两个字段,name
和 age
。如果这两条信息来自不同的真实来源(我并不总是想同时获取两者),我可以为每个字段实现一个 PetResolver
class 解析器:
@Resolver(() => Pet)
export class PetResolver {
@Query(() => Pet)
pet(): Pet {
return {};
}
@ResolveField()
name(): Promise<string> {
return Promise.resolve('Spot');
}
@ResolveField(() => Int)
age(): Promise<number> {
return Promise.resolve(2);
}
}
可以这样使用:
query GetPet {
pet {
name
}
}
这行得通并且可以确保每个字段的值仅在请求时获取,但是如果我想在我的 User
类型上有一个 pet
字段,我可以像这样查询:
query GetUserWithPet {
currentUser {
email
pet {
name
}
}
}
应用相同的原理,我可以创建一个 UserResolver class,如下所示:
@Resolver(() => User)
export class UserResolver {
@Query(() => User)
@UseGuards(AuthCognitoGuard)
currentUser(@CurrentUser() user: IdTokenPayload): User {
return {
id: user.sub,
email: user.email,
};
}
@ResolveField()
pet(@Parent() user: User): Promise<Pet> {
return petService.getPetForUserId(user.id);
}
}
但是 PetService
实现如果只想获取相关数据就必须知道请求了哪些字段。
A) 有没有办法在 UserResolver
中使用 PetResolver
来利用单独的字段解析逻辑?
B) 如果不是,使用 NestJS 代码优先约定确定查询中请求了哪些字段的最佳方法是什么?
C) 这是考虑 GraphQL 查询的“错误”方式吗?最佳实践是否要求我保留单独的解析器并使用如下查询:
query GetUserWithPet {
currentUser {
email
}
pet {
name
}
}
用户应该包含一些 petIds
[数组] 值(内部,数据库存储 field/column)...
... 可以解析 pets: [Pet]
prop/relation - Pet
列表 ...
... 就像 starshipIDs
在 https://graphql.org/learn/execution/
注意:宠物服务被询问使用宠物id的记录。
...但当然 pet 可以包含一些 ownerId
(仅或显式可见,数据库存储 field/column)使得解析 owner: User
prop [reverse] 关系成为可能 - 这你可以这样:
query PetWithOwner {
pet (id: "someID") {
id
name
owner {
id
email
# more pets?
pets {
id
name
# you can loop it ;)
owner {
id
email
pet.owner
字段解析器只能 return { id: ownerId }
对象(部分响应)...服务器将尝试解析 'missing'(查询需要)email
道具使用 User
(owner
是 User
类型)类型解析器,将 id 作为参数传递(check/console.log parent
和 args
解析器参数)。您不必在 pet.owner
字段解析器中[相同] 'manually'。
查询必填字段...
... [选择集] 可以从 info
对象中读取 - 第 4 个解析器 arg - 阅读 docs/tutorial 了解详细信息