Apollo/GraphQl - 类型必须是输入类型 [英] Apollo / GraphQl - Type must be Input type

查看:26
本文介绍了Apollo/GraphQl - 类型必须是输入类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在学习过程中以及将 Apollo 和 graphQL 集成到我的一个项目中的过程中与大家联系.到目前为止一切顺利,但现在我正在尝试进行一些更改,并且正在为 Input 类型和 Query 类型苦苦挣扎.我觉得它比它应该的复杂得多,因此我正在寻找关于我应该如何管理我的情况的建议.我在网上找到的例子总是有非常基本的模式,但现实总是更复杂,因为我的模式很大,看起来如下(我只会复制一部分):

类型计算{_id:字符串!用户 ID:字符串!数据:计算数据最后更新: Int名称:字符串}类型计算数据{负载:[负载]验证:布尔值x:浮动y:浮动z:浮动输入:[输入]指标:布尔值}

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

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

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

我的解析器如下:

导出默认解析器 = {突变:{保存计算(对象,参数,上下文){if(context.user && context.user._id){constcalculationId = Calculations.insert({用户 ID:context.user._id,数据:args.data,名称:args.name})返回Calculations.findOne({_id:calculationId})}throw new Error('需要一个帐户来保存计算')}}}

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

export const SAVE_CALCULATION = gql`突变 saveCalculation($data: CalculationData!, $name: String!){保存计算(数据:$数据,名称:$名称){_ID}}`

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

{(sav​​eCalculation, { data }) =>(<div onClick={() =>saveCalculation({ variables : { data: this.state, name:'name calcul' }})}>SAVE</div>}}</突变>

现在我收到以下错误:

<块引用>

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

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

解决方案

来自规范:><块引用>

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

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

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

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

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

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

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

Reaching to you all as I am in the learning process and integration of Apollo and graphQL into one of my projects. So far it goes ok but now I am trying to have some mutations and I am struggling with the Input type and Query type. I feel like it's way more complicated than it should be and therefore I am looking for advice on how I should manage my situation. Examples I found online are always with very basic Schemas but the reality is always more complex as my Schema is quite big and look as follow (I'll copy just a part):

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

}

Then Inputs and Loads are defined, and so on...

For this I want a mutation to save the "Calculation", so in the same file I have this:

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

My resolver is as follow:

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')
        }
    }
}

Then my mutation is the following : import gql from 'graphql-tag';

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

Finally I am using the Mutation component to try to save the data:

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

Now I get the following error :

[GraphQL error]: Message: The type of Mutation.saveCalculation(data:) must be Input Type but got: CalculationData!., Location: undefined, Path: undefined

From my research and some other SO posts, I get that I should define Input type in addition to the Query type but Input type can only avec Scalar types but my schema depends on other schemas (and that is not scalar). Can I create Input types depending on other Input types and so on when the last one has only scalar types? I am kinda lost cause it seems like a lot of redundancy. Would very much appreciate some guidance on the best practice. I am convinced Apollo/graphql could bring me quite good help over time on my project but I have to admit it is more complicated than I thought to implement it when the Schemas are a bit complex. Online examples generally stick to a String and a Boolean.

解决方案

From the 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.

In other words, you can't use regular GraphQLObjectTypes as the type for an GraphQLInputObjectType field -- you must use another GraphQLInputObjectType.

When you write out your schema using SDL, it may seem redundant to have to create a Load type and a LoadInput input, especially if they have the same fields. However, under the hood, the types and inputs you define are turned into very different classes of object, each with different properties and methods. There is functionality that is specific to a GraphQLObjectType (like accepting arguments) that doesn't exist on an GraphQLInputObjectType -- and vice versa.

Trying to use in place of another is kind of like trying to put a square peg in a round hole. "I don't know why I need a circle. I have a square. They both have a diameter. Why do I need both?"

Outside of that, there's a good practical reason to keep types and inputs separate. That's because in plenty of scenarios, you will expose plenty of fields on the type that you won't expose on the input.

For example, your type might include derived fields that are actually a combination of the underlying data. Or it might include fields to relationships with other data (like a friends field on a User). In both these case, it wouldn't make sense to make these fields part of the data that's submitted as as argument for some field. Likewise, you might have some input field that you wouldn't want to expose on its type counterpart (a password field comes to mind).

这篇关于Apollo/GraphQl - 类型必须是输入类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆