Apollo / GraphQl - 类型必须是输入类型

Apollo / GraphQl - Type must be Input type

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

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

}

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

为此我想要一个突变来保存 "Calculation",所以在同一个文件中我有这个:

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 error]: Message: The type of Mutation.saveCalculation(data:) must be Input Type but got: CalculationData!., Location: undefined, Path: undefined

从我的研究和其他一些 SO 帖子中,我了解到除了查询类型之外我还应该定义输入类型但输入类型只能 avec 标量类型但我的模式依赖于其他模式(这不是标量) .当最后一个只有标量类型时,我可以根据其他输入类型等创建输入类型吗?我有点迷路,因为它似乎有很多冗余。非常感谢有关最佳实践的一些指导。我相信 Apollo/graphql 随着时间的推移可以给我的项目带来很好的帮助,但我不得不承认它比我想象的更复杂复杂的。在线示例通常坚持一个字符串和一个布尔值。

是的,你可以:

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

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

来自spec:

Fields may accept arguments to configure their behavior. These inputs are often scalars or enums, but they sometimes need to represent more complex values.

A GraphQL Input Object defines a set of input fields; the input fields are either scalars, enums, or other input objects. This allows arguments to accept arbitrarily complex structs.

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

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

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

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

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