我有一个类似的架构:
scalar Date
schema {
query: Query
}
type Query {
user(id: ID!): User
messages(userId: ID!): [ChatMessage!]!
}
type User {
id: ID!
username: String!
email: String!
}
type ChatMessage {
id: ID!
content: String!
time: Date!
user: User!
}
我想进行一个操作,以便为用户获取所有消息,但是由于User
和ChatMessage
位于单独的数据库表中,因此我需要执行两个查询(一个查询要获取ChatMessages
和一个获得User
的对象),所以我认为我应该像这样建模:
query findMessagesForUser($userId: ID!) {
messages(userId: $userId) {
id
content
user(id: $userId) {
username
email
}
}
}
这将在架构上返回解析错误:
GraphQLDocumentError:“ ChatMessage.user”字段上的未知参数“ id”。
那么,如何将$userId
参数传递给ChatMessage.user
的解析器?
答案 0 :(得分:1)
在您的模式中,您已经在Query.user方法上定义了一个id输入。在查询中,您尝试向Message.user属性提供一个ID,但是尚未在架构中定义此输入。
如果您想在ChatMessage.user上接受一个ID,则需要将其定义为:
type ChatMessage {
id: ID!
content: String!
time: Date!
user(id: ID!): User
}
但是,以这种方式构造模式(至少对我来说)并没有任何意义,我假设每封邮件只有一个用户(作者)。
如@xadm所示,您在ChatMessage级别解析的对象将作为第一个参数传递到用户解析器中。
即使您没有在架构中公开ChatMessage.userId(没关系),也可能仍将其加载到后端(ChatMessage表中的外键值)并在对象上进行设置用于解析ChatMessage。
这样,您将使用父ChatMessage对象参数的userId属性(延迟)加载(延迟)查询中包含的用户IF(请记住,您无需通过架构公开ChatMessage.userId,它只是在用于解析ChatMessage的对象。
我会考虑更像这样建模(将过滤器输入用作其他人为的示例):
type Query {
user(id: ID!): User
messages(filter: MessageFilter): [ChatMessage!]!
}
type MessageFilter {
search: String
paging: PagingFilter
}
type PagingFilter {
after: ID!
pageSize: Int!
}
type User {
id: ID!
username: String!
email: String!
messages(filter: MessageFilter): [ChatMessage!]!
}
在解析器图中,您可以连接相同的功能来解析用户级别和查询级别的消息。唯一的区别是您在查询级别将没有userId。
如果消费者想查看/搜索所有用户的消息,则使用顶级查询消息方法。
{
messages({search: 'graphql'}) {
id,
content,
time
}
}
如果消费者想查看/搜索一个用户的消息,请通过顶级“查询用户”方法进入消息。
{
user(id: 3) {
messages({search: 'graphql'}) {
id,
content,
time
}
}
}
该过滤器示例是人为设计的,但可以提供用于加载消息的基本分页。
apollographql.com/docs/graphql-tools/解析器