当子字段在不同的接口中时,为什么会发生冲突?

问题描述 投票:1回答:1

我试图查询一个MongoDB文档(trivia)使用GraphQL(Apollo Server),但其中一个文档字段有问题。

LightningRoundQuestion.answerPictureRoundPicture.answer 应返回 StringMultipleChoiceRoundQuestion.answer 应该返回一个 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."

我不太确定下一步该怎么做,我看了一下: 阿波罗文件中的别名,但那里没有什么帮助。

node.js graphql apollo graphql-js apollo-server
1个回答
1
投票

当使用抽象类型时,这是个小问题,是GraphQL处理合并字段选择的结果。归结起来就是,如果你在同一个选择集中多次请求一个具有相同名称(或别名)的字段,该字段必须返回相同的类型。在上面的模式中,它不需要 -- 问题可以有相同的类型。[LightningRoundQuestion][PictureRoundPicture] 等等。

详细的解释,请看 本节 的规范。

有两个变通的方法。在客户端,你可以使用别名来确保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, themepointValue 因为这些字段在你所有的实现类型中具有相同的类型。

© www.soinside.com 2019 - 2024. All rights reserved.