为什么子字段在不同界面时会发生冲突?
Why do subfields conflict when they are in different interfaces?
我正在尝试使用 GraphQL (Apollo Server) 查询单个 MongoDB 文档 (trivia
),但我在处理其中一个文档字段时遇到问题。
LightningRoundQuestion.answer
和 PictureRoundPicture.answer
应该 return 和 String
,MultipleChoiceRoundQuestion.answer
应该 return 和 Int
。查看架构:
schema
const typeDefs = gql`
# ROOT TYPES ==================================================
type Query {
trivia(_id: String!): Trivia
}
# INTERFACES ==================================================
interface Round {
type: String!
theme: String!
pointValue: Int!
}
type LightningRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [LightningRoundQuestion]
}
type MultipleChoiceRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [MultipleChoiceRoundQuestion]
}
type PictureRound implements Round {
type: String!
theme: String!
pointValue: Int!
pictures: [PictureRoundPicture]
}
# QUERY TYPES =================================================
type LightningRoundQuestion {
question: String!
answer: String!
}
type MultipleChoiceRoundQuestion {
question: String!
options: [String!]!
answer: Int!
}
type PictureRoundPicture {
url: String!
answer: String!
}
type Trivia {
_id: String!
createdAt: String!
triviaId: String!
triviaPin: String!
host: String!
rounds: [Round]!
tieBreaker: TieBreaker!
}
type TieBreaker {
question: String
answer: Int
}
`
resolvers & server
const resolvers = {
Query: {
trivia: async (root, { _id }) => {
return triviaCollection.findOne(ObjectId(_id))
}
},
Round: {
__resolveType(obj) {
if (obj.type === 'multipleChoice') {
return 'MultipleChoiceRound'
} else if (obj.type === 'lightning') {
return 'LightningRound'
} else if (obj.type === 'picture') {
return 'PictureRound'
}
}
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`)
})
query
query {
trivia(_id: "5e827a4e1c9d4400009fea32") {
_id
createdAt
triviaId
triviaPin
host
rounds {
... on LightningRound {
questions {
question
answer
}
}
... on MultipleChoiceRound {
questions {
question
options
answer
}
}
... on PictureRound {
pictures {
url
answer
}
}
}
}
}
我收到错误消息:
"message": "Fields \"questions\" conflict because subfields \"answer\" conflict because they return conflicting types \"String!\" and \"Int!\". Use different aliases on the fields to fetch both if this was intentional."
不太确定下一步该做什么,我查看了 Alias in the Apollo documentation,但没有什么帮助。
这在使用抽象类型时有点棘手,并且由于 GraphQL 如何处理合并字段选择而发生。归结为,如果您在同一选择集中多次请求同名(或别名)的字段,则该字段必须 return 相同类型。在上面的模式中,它不是——问题可以有 [LightningRoundQuestion]
或 [PictureRoundPicture]
等类型。
有关详细说明,请参阅规范的 this section。
对此有两种解决方法。在客户端,您可以使用别名来确保 GraphQL 不会首先尝试合并字段:
rounds {
... on LightningRound {
lightningQuestions: questions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions: questions {
question
options
answer
}
}
}
当您无法更改架构时,这是您最好的选择。但是,您也可以只更改服务器端的字段名称,以获得更好的客户端 DX。
rounds {
... on LightningRound {
lightningQuestions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions {
question
options
answer
}
}
}
请注意,我们不必对 type
、theme
或 pointValue
执行此操作,因为这些字段在您的所有实施类型中具有相同的类型。
我正在尝试使用 GraphQL (Apollo Server) 查询单个 MongoDB 文档 (trivia
),但我在处理其中一个文档字段时遇到问题。
LightningRoundQuestion.answer
和 PictureRoundPicture.answer
应该 return 和 String
,MultipleChoiceRoundQuestion.answer
应该 return 和 Int
。查看架构:
schema
const typeDefs = gql`
# ROOT TYPES ==================================================
type Query {
trivia(_id: String!): Trivia
}
# INTERFACES ==================================================
interface Round {
type: String!
theme: String!
pointValue: Int!
}
type LightningRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [LightningRoundQuestion]
}
type MultipleChoiceRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [MultipleChoiceRoundQuestion]
}
type PictureRound implements Round {
type: String!
theme: String!
pointValue: Int!
pictures: [PictureRoundPicture]
}
# QUERY TYPES =================================================
type LightningRoundQuestion {
question: String!
answer: String!
}
type MultipleChoiceRoundQuestion {
question: String!
options: [String!]!
answer: Int!
}
type PictureRoundPicture {
url: String!
answer: String!
}
type Trivia {
_id: String!
createdAt: String!
triviaId: String!
triviaPin: String!
host: String!
rounds: [Round]!
tieBreaker: TieBreaker!
}
type TieBreaker {
question: String
answer: Int
}
`
resolvers & server
const resolvers = {
Query: {
trivia: async (root, { _id }) => {
return triviaCollection.findOne(ObjectId(_id))
}
},
Round: {
__resolveType(obj) {
if (obj.type === 'multipleChoice') {
return 'MultipleChoiceRound'
} else if (obj.type === 'lightning') {
return 'LightningRound'
} else if (obj.type === 'picture') {
return 'PictureRound'
}
}
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`)
})
query
query {
trivia(_id: "5e827a4e1c9d4400009fea32") {
_id
createdAt
triviaId
triviaPin
host
rounds {
... on LightningRound {
questions {
question
answer
}
}
... on MultipleChoiceRound {
questions {
question
options
answer
}
}
... on PictureRound {
pictures {
url
answer
}
}
}
}
}
我收到错误消息:
"message": "Fields \"questions\" conflict because subfields \"answer\" conflict because they return conflicting types \"String!\" and \"Int!\". Use different aliases on the fields to fetch both if this was intentional."
不太确定下一步该做什么,我查看了 Alias in the Apollo documentation,但没有什么帮助。
这在使用抽象类型时有点棘手,并且由于 GraphQL 如何处理合并字段选择而发生。归结为,如果您在同一选择集中多次请求同名(或别名)的字段,则该字段必须 return 相同类型。在上面的模式中,它不是——问题可以有 [LightningRoundQuestion]
或 [PictureRoundPicture]
等类型。
有关详细说明,请参阅规范的 this section。
对此有两种解决方法。在客户端,您可以使用别名来确保 GraphQL 不会首先尝试合并字段:
rounds {
... on LightningRound {
lightningQuestions: questions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions: questions {
question
options
answer
}
}
}
当您无法更改架构时,这是您最好的选择。但是,您也可以只更改服务器端的字段名称,以获得更好的客户端 DX。
rounds {
... on LightningRound {
lightningQuestions {
question
answer
}
}
... on MultipleChoiceRound {
multipleChoiceQuestions {
question
options
answer
}
}
}
请注意,我们不必对 type
、theme
或 pointValue
执行此操作,因为这些字段在您的所有实施类型中具有相同的类型。