GraphQL 中的输入类型有什么意义?
What's the point of input type in GraphQL?
你能解释一下为什么如果变异的输入参数是对象,它应该是输入类型吗?我认为更简单的是重用 type 而不提供 id.
例如:
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
}
对于小对象来说还好,但是当你有大量的对象在模式中有 10 个以上的属性时,这将成为一种负担。
杰西的评论是正确的。对于更正式的回答,这里是 GraphQL documentation on input types 的摘录:
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.
更新
发布后,我发现循环引用实际上是可以接受的,只要它们是 nilable(否则它会声明一个无限链)。但是,仍然存在其他限制(例如接口)似乎需要一个单独的输入类型系统。
来自规范:
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. For this reason, input objects have a separate type in the system.
那是 "official reason",但有几个实际原因导致您不能将对象类型用作输入对象类型或将对象类型用作输入对象类型:
功能
对象类型和输入对象类型都有字段,但是这些字段有不同的属性,反映了模式如何使用这些类型。您的架构可能会为对象类型的字段定义参数和某种解析器函数,但这些属性在输入上下文中没有意义(即您不能 resolve 输入对象的字段——它已经有一个明确的值)。同样,只能为输入对象类型字段提供默认值,不能为对象类型字段提供默认值。
换句话说,这看起来像是重复:
type Student {
name: String
grade: Grade
}
input StudentInput {
name: String
grade: Grade
}
但是添加特定于对象类型或输入对象类型的功能可以清楚地表明它们的行为不同:
type Student {
name(preferred: Boolean): String
grade: Grade
}
input StudentInput {
name: String
grade: Grade = F
}
类型系统限制
GraphQL 中的类型分为输出类型和输入类型。
输出类型是可以 returned 作为 GraphQL 服务产生的响应的一部分的类型。输入类型是字段或指令参数的有效输入类型。
这两组之间存在重叠(即标量、枚举、列表和非空值)。但是,抽象类型,如联合和接口在输入上下文中没有意义,不能用作输入。将对象类型和输入对象类型分开可以确保抽象类型永远不会在需要输入类型的地方使用。
架构设计
在您的模式中表示实体时,某些实体可能确实 "share fields" 在它们各自的输入和输出类型之间:
type Student {
firstName: String
lastName: String
grade: Grade
}
input StudentInput {
firstName: String
lastName: String
grade: Grade
}
但是,对象类型可以(并且实际上经常这样做)为非常复杂的数据结构建模:
type Student {
fullName: String!
classes: [Class!]!
address: Address!
emergencyContact: Contact
# etc
}
虽然这些结构 可能 转化为适当的输入(我们创建了一个 Student,因此我们也传入了一个代表他们地址的对象),但它们通常不会——也就是说,也许我们需要通过 class ID 和部门 ID 指定学生的 classes,而不是对象。同样,我们可能有想要 return 但不想改变的字段,反之亦然(如 password
字段)。
此外,即使对于相对简单的实体,我们也经常对对象类型及其 "counterpart" 输入对象之间的可空性有不同的要求。通常我们希望保证一个字段也将在响应中被 returned,但我们不想在我们的输入中创建相同的字段。例如,
type Student {
firstName: String!
lastName: String!
}
input StudentInput {
firstName: String
lastName: String
}
最后,在许多模式中,给定实体的对象类型和输入对象类型之间通常没有一对一的映射。一种常见的模式是针对不同的操作使用单独的输入对象类型来进一步微调模式级输入验证:
input CreateUserInput {
firstName: String!
lastName: String!
email: String!
password: String!
}
input UpdateUserInput {
email: String
password: String
}
所有这些示例都说明了一个重点——虽然输入对象类型有时可能会镜像对象类型,但由于业务需求,您不太可能在生产模式中看到这种情况。
只是因为您不想将 public API 耦合到您的域模型或数据库模型。传入数据在响应数据中的表示方式不同。您不想为传入和输出重复使用相同的数据类型......或者您会将您的用户完全绑定到您的域或数据库模型,这意味着您更改的任何内容都可能破坏您的客户
输入类型本质上是RequestTypes。例如,当您考虑交付机制(发出请求的客户端)与交付机制与控制器下方的业务逻辑之间的边界时,您会想到六边形架构。
你能解释一下为什么如果变异的输入参数是对象,它应该是输入类型吗?我认为更简单的是重用 type 而不提供 id.
例如:
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
}
对于小对象来说还好,但是当你有大量的对象在模式中有 10 个以上的属性时,这将成为一种负担。
杰西的评论是正确的。对于更正式的回答,这里是 GraphQL documentation on input types 的摘录:
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.
更新
发布后,我发现循环引用实际上是可以接受的,只要它们是 nilable(否则它会声明一个无限链)。但是,仍然存在其他限制(例如接口)似乎需要一个单独的输入类型系统。
来自规范:
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. For this reason, input objects have a separate type in the system.
那是 "official reason",但有几个实际原因导致您不能将对象类型用作输入对象类型或将对象类型用作输入对象类型:
功能
对象类型和输入对象类型都有字段,但是这些字段有不同的属性,反映了模式如何使用这些类型。您的架构可能会为对象类型的字段定义参数和某种解析器函数,但这些属性在输入上下文中没有意义(即您不能 resolve 输入对象的字段——它已经有一个明确的值)。同样,只能为输入对象类型字段提供默认值,不能为对象类型字段提供默认值。
换句话说,这看起来像是重复:
type Student {
name: String
grade: Grade
}
input StudentInput {
name: String
grade: Grade
}
但是添加特定于对象类型或输入对象类型的功能可以清楚地表明它们的行为不同:
type Student {
name(preferred: Boolean): String
grade: Grade
}
input StudentInput {
name: String
grade: Grade = F
}
类型系统限制
GraphQL 中的类型分为输出类型和输入类型。
输出类型是可以 returned 作为 GraphQL 服务产生的响应的一部分的类型。输入类型是字段或指令参数的有效输入类型。
这两组之间存在重叠(即标量、枚举、列表和非空值)。但是,抽象类型,如联合和接口在输入上下文中没有意义,不能用作输入。将对象类型和输入对象类型分开可以确保抽象类型永远不会在需要输入类型的地方使用。
架构设计
在您的模式中表示实体时,某些实体可能确实 "share fields" 在它们各自的输入和输出类型之间:
type Student {
firstName: String
lastName: String
grade: Grade
}
input StudentInput {
firstName: String
lastName: String
grade: Grade
}
但是,对象类型可以(并且实际上经常这样做)为非常复杂的数据结构建模:
type Student {
fullName: String!
classes: [Class!]!
address: Address!
emergencyContact: Contact
# etc
}
虽然这些结构 可能 转化为适当的输入(我们创建了一个 Student,因此我们也传入了一个代表他们地址的对象),但它们通常不会——也就是说,也许我们需要通过 class ID 和部门 ID 指定学生的 classes,而不是对象。同样,我们可能有想要 return 但不想改变的字段,反之亦然(如 password
字段)。
此外,即使对于相对简单的实体,我们也经常对对象类型及其 "counterpart" 输入对象之间的可空性有不同的要求。通常我们希望保证一个字段也将在响应中被 returned,但我们不想在我们的输入中创建相同的字段。例如,
type Student {
firstName: String!
lastName: String!
}
input StudentInput {
firstName: String
lastName: String
}
最后,在许多模式中,给定实体的对象类型和输入对象类型之间通常没有一对一的映射。一种常见的模式是针对不同的操作使用单独的输入对象类型来进一步微调模式级输入验证:
input CreateUserInput {
firstName: String!
lastName: String!
email: String!
password: String!
}
input UpdateUserInput {
email: String
password: String
}
所有这些示例都说明了一个重点——虽然输入对象类型有时可能会镜像对象类型,但由于业务需求,您不太可能在生产模式中看到这种情况。
只是因为您不想将 public API 耦合到您的域模型或数据库模型。传入数据在响应数据中的表示方式不同。您不想为传入和输出重复使用相同的数据类型......或者您会将您的用户完全绑定到您的域或数据库模型,这意味着您更改的任何内容都可能破坏您的客户
输入类型本质上是RequestTypes。例如,当您考虑交付机制(发出请求的客户端)与交付机制与控制器下方的业务逻辑之间的边界时,您会想到六边形架构。