【问题标题】:Apollo / GraphQl - Type must be Input typeApollo / GraphQl - 类型必须是输入类型
【发布时间】:2019-03-15 15:23:18
【问题描述】:

在学习过程中与大家联系,并将 Apollo 和 graphQL 集成到我的一个项目中。到目前为止一切正常,但现在我正在尝试进行一些突变,并且我正在努力处理输入类型和查询类型。我觉得它比应有的复杂得多,因此我正在寻找有关如何管理我的情况的建议。我在网上找到的示例总是带有非常基本的 Schema,但现实总是更复杂,因为我的 Schema 很大并且看起来如下(我将只复制一部分):

type Calculation {
    _id: String!
    userId: String!
    data: CalculationData
    lastUpdated: Int
    name: String
}

type CalculationData {
    Loads: [Load]
    validated: Boolean
    x: Float
    y: Float
    z: Float
    Inputs: [Input]
    metric: Boolean

}

然后定义输入和负载,依此类推...

为此,我想要一个突变来保存“​​计算”,所以在同一个文件中我有这个:

type Mutation {
    saveCalculation(data: CalculationData!, name: String!): Calculation
}

我的解析器如下:

export default resolvers = {
    Mutation: {
        saveCalculation(obj, args, context) {
            if(context.user && context.user._id){
                const calculationId = Calculations.insert({
                    userId: context.user._id,
                    data: args.data,
                    name: args.name
                })
                return Calculations.findOne({ _id: calculationId})
            }
            throw new Error('Need an account to save a calculation')
        }
    }
}

然后我的突变如下: 从'graphql-tag'导入gql;

export const SAVE_CALCULATION = gql`
    mutation saveCalculation($data: CalculationData!, $name: String!){
        saveCalculation(data: $data, name: $name){
            _id
        }
    }
`

最后我正在使用 Mutation 组件来尝试保存数据:

<Mutation mutation={SAVE_CALCULATION}>
    {(saveCalculation, { data }) => (
        <div onClick={() => saveCalculation({ variables : { data: this.state, name:'name calcul' }})}>SAVE</div>
    }}
</Mutation>

现在我收到以下错误:

[GraphQL 错误]:消息:Mutation.saveCalculation(data:) 的类型 必须是输入类型,但得到:CalculationData!.,位置:未定义, 路径:未定义

从我的研究和其他一些 SO 帖子中,我知道除了 Query 类型之外,我还应该定义 Input 类型,但 Input 类型只能是 avec Scalar 类型,但我的模式取决于其他模式(这不是标量)。当最后一个只有标量类型时,我可以根据其他输入类型等创建输入类型吗?我有点迷路了,因为它似乎有很多冗余。非常感谢有关最佳实践的一些指导。我相信 Apollo/graphql 可以随着时间的推移在我的项目上为我带来很好的帮助,但我不得不承认,当 Schema 有点复杂时,实现它比我想象的要复杂。在线示例通常坚持使用 String 和 Boolean。

【问题讨论】:

    标签: meteor graphql apollo


    【解决方案1】:

    来自spec

    字段可以接受参数来配置其行为。这些输入通常是标量或枚举,但它们有时需要表示更复杂的值。

    一个 GraphQL 输入对象定义了一组输入字段;输入字段可以是标量、枚举或其他输入对象。这允许参数接受任意复杂的结构。

    换句话说,您不能使用常规的GraphQLObjectTypes 作为GraphQLInputObjectType 字段的类型——您必须使用另一个GraphQLInputObjectType

    当您使用 SDL 编写架构时,必须创建 Load 类型和 LoadInput 输入似乎是多余的,尤其是在它们具有相同字段的情况下。然而,在底层,你定义的类型和输入会变成非常不同的对象类,每个类都有不同的属性和方法。 GraphQLObjectType 特有的功能(例如接受参数)在 GraphQLInputObjectType 上不存在——反之亦然。

    试图代替另一个使用有点像试图将一个方形钉子放在一个圆孔中。 “我不知道为什么我需要一个圆。我有一个正方形。它们都有直径。为什么我都需要?”

    除此之外,还有一个很好的实际理由将类型和输入分开。这是因为在很多情况下,您会在类型上公开大量字段,而不会在输入上公开。

    例如,您的类型可能包含实际上是基础数据组合的派生字段。或者它可能包含与其他数据的关系的字段(例如User 上的friends 字段)。在这两种情况下,将这些字段作为作为某些字段的参数提交的数据的一部分是没有意义的。同样,您可能有一些您不想在其对应类型上公开的输入字段(想到一个 password 字段)。

    【讨论】:

    • 再次感谢有关 graphQL/Apollo 的明确答复
    • 我不知道这个答案意味着“必须创建一个负载类型和一个负载输入输入”
    • @YanickRochon GraphQL 具有由 type 关键字指定的 object types 和由 input 关键字设计的 input object types。前者用于输出,后者用于输入。
    • @DanielRearden 感谢您的澄清,我开始使用 GraphQL,还有很多东西需要学习。
    【解决方案2】:

    是的,您可以:

    输入对象类型上的字段本身可以引用输入对象类型,但您不能在架构中混合输入和输出类型。输入对象类型的字段也不能有参数。

    输入类型是除了普通类型之外的定义。通常它们会有一些差异,例如输入不会有 id 或 createdAt 字段。

    【讨论】:

      猜你喜欢
      • 2016-01-17
      • 2018-01-30
      • 2020-04-23
      • 2016-10-14
      • 2018-06-30
      • 2018-12-18
      • 2019-05-13
      • 2016-12-31
      相关资源
      最近更新 更多