简体   繁体   English

GraphQL 中输入类型的重点是什么?

[英]What's the point of input type in GraphQL?

Could you please explain why if input argument of mutation is object it should be input type ?你能解释一下为什么如果mutation的输入参数是object它应该是输入类型吗? I think much simpler just reuse type without providing id.我认为更简单的只是重用类型而不提供 id。

For example:例如:

type Sample {
  id: String
  name: String
}

input SampleInput {
  name: String
}

type RootMutation {
  addSample(sample: Sample): Sample  # <-- instead of it should be
  addSample(sample: SampleInput): Sample
}

It's okay for small object, but when you have plenty of objects with 10+ properties in schema that'll become a burden.对于小对象来说是可以的,但是当您在架构中有大量具有 10 多个属性的对象时,这将成为一种负担。

From the spec:从规范:

The GraphQL Object type (ObjectTypeDefinition)... is inappropriate for re‐use [as an input], because Object types can contain fields that define arguments or contain references to interfaces and unions, neither of which is appropriate for use as an input argument. GraphQL 对象类型 (ObjectTypeDefinition)... 不适合重用 [作为输入],因为对象类型可以包含定义参数的字段或包含对接口和联合的引用,这两者都不适合用作输入参数. For this reason, input objects have a separate type in the system.因此,输入对象在系统中具有单独的类型。

That's the "official reason", but there's several practical reasons why you can't use an object type as an input object type or use an object type as an input object type:这是“官方原因”,但有几个实际原因为什么不能使用对象类型作为输入对象类型或使用对象类型作为输入对象类型:

Functionality功能

Object types and input object types both have fields, however those fields have different properties that reflect how these types are used by the schema.对象类型和输入对象类型都具有字段,但是这些字段具有反映模式如何使用这些类型的不同属性。 Your schema will potentially define arguments and some kind of resolver function for an object type's fields, but these properties don't make sense in an input context (ie you can't resolve an input object's field -- it already has an explicit value).您的架构可能会为对象类型的字段定义参数和某种解析器函数,但这些属性在输入上下文中没有意义(即您无法解析输入对象的字段——它已经具有显式值) . Similarly, default values can only be provided for input object type fields, and not object type fields.同样,只能为输入对象类型字段提供默认值,而不能为对象类型字段提供默认值。

In other words, this may seem like duplication:换句话说,这看起来像是重复:

type Student {
  name: String
  grade: Grade
}

input StudentInput {
  name: String
  grade: Grade
}

But adding features specific to either object types or input object types makes it clear that they behave differently:但是添加特定于对象类型或输入对象类型的功能可以清楚地表明它们的行为不同:

type Student {
  name(preferred: Boolean): String
  grade: Grade
}

input StudentInput {
  name: String
  grade: Grade = F
}

Type system limitations类型系统限制

Types in GraphQL are grouped into output types and input types . GraphQL 中的类型分为输出类型输入类型

Output types are types that may be returned as part of a response produced by a GraphQL service.输出类型是可以作为 GraphQL 服务产生的响应的一部分返回的类型。 Input types are types that are valid inputs for field or directive arguments.输入类型是字段或指令参数的有效输入类型。

There's overlap between these two groups (ie scalars, enums, lists and non-nulls).这两个组(即标量、枚举、列表和非空值)之间存在重叠。 However, abstract types like unions and interfaces don't make sense in an input context and cannot be used as inputs.但是,联合和接口等抽象类型在输入上下文中没有意义,不能用作输入。 Separating object types and input object types allows you to ensure that an abstract type is never used where an input type is expected.分离对象类型和输入对象类型允许您确保在需要输入类型的地方永远不会使用抽象类型。

Schema design架构设计

When representing an entity in your schema, it's likely that some entities will indeed "share fields" between their respective input and output types:在您的架构中表示实体时,某些实体可能确实会在其各自的输入和输出类型之间“共享字段”:

type Student {
  firstName: String
  lastName: String
  grade: Grade
}

input StudentInput {
  firstName: String
  lastName: String
  grade: Grade
}

However, object types can (and in reality frequently do) model very complex data structures:但是,对象类型可以(并且实际上经常这样做)对非常复杂的数据结构进行建模:

type Student {
  fullName: String!
  classes: [Class!]!
  address: Address!
  emergencyContact: Contact
  # etc
}

While these structures may translate into appropriate inputs (we create a Student, so we also pass in an object representing their address), often they do not -- ie maybe we need to specify the student's classes by class ID and section ID, not an object.虽然这些结构可能会转化为适当的输入(我们创建了一个 Student,所以我们也传入了一个代表他们地址的对象),但通常它们不会——也就是说,也许我们需要通过类 ID 和部分 ID 来指定学生的班级,而不是目的。 Similarly, we may have fields that we want to return, but don't want to mutate, or vice versa (like a password field).类似地,我们可能有想要返回但不想改变的字段,反之亦然(如password字段)。

Moreover, even for relatively simple entities, we often have different requirements around nullability between object types and their "counterpart" input objects.此外,即使对于相对简单的实体,我们通常对对象类型及其“对应”输入对象之间的可空性有不同的要求。 Often we want to guarantee that a field will also be returned in a response, but we don't want to make the same fields required in our input.通常我们想保证一个字段也会在响应中返回,但我们不想在我们的输入中使用相同的字段。 For example,例如,

type Student {
  firstName: String!
  lastName: String!
}

input StudentInput {
  firstName: String
  lastName: String
}

Lastly, in many schemas, there's often not a one-to-one mapping between object type and input object type for a given entity.最后,在许多模式中,给定实体的对象类型和输入对象类型之间通常没有一对一的映射。 A common pattern is to utilize separate input object types for different operations to further fine-tune the schema-level input validation:一个常见的模式是为不同的操作使用不同的输入对象类型来进一步微调模式级输入验证:

input CreateUserInput {
  firstName: String!
  lastName: String!
  email: String!
  password: String!
}

input UpdateUserInput {
  email: String
  password: String
}

All of these examples illustrate an important point -- while an input object type may mirror an object type some of the time, you're much less likely to see that in production schemas due to business requirements.所有这些示例都说明了一个重要点——虽然输入对象类型有时可能会反映对象类型,但由于业务需求,您在生产模式中不太可能看到这种情况。

Jesse's comment is correct.杰西的评论是正确的。 For more formal answer, here is the excerpt from GraphQL documentation on input types :有关更正式的答案,以下是有关输入类型的 GraphQL 文档的摘录:

The Object type defined above is inappropriate for re‐use here, because Objects can contain fields that express circular references or references to interfaces and unions, neither of which is appropriate for use as an input argument.上面定义的对象类型不适合在这里重用,因为对象可以包含表达循环引用或对接口和联合的引用的字段,这两者都不适合用作输入参数。 For this reason, input objects have a separate type in the system.因此,输入对象在系统中具有单独的类型。

UPDATE更新

Since posting it, I found that circular references actually are acceptable, so long as those are nilable (or else it would declare an infinite chain).自从发布后,我发现循环引用实际上是可以接受的,只要它们是 nilable (否则它会声明一个无限链)。 But, still there are other limitations (eg interfaces) that seem to necessitate a separate type system for inputs.但是,仍然存在其他限制(例如接口),似乎需要一个单独的输入类型系统。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM