GraphQL 输入类型可以继承自其他类型或接口吗?
Can a GraphQL input type inherit from another type or interface?
是否可以对 GraphQL 输入类型使用继承?
类似的东西(当然,这不适用于输入类型):
interface UserInputInterface {
firstName: String
lastName: String
}
input UserInput implements UserInputInterface {
password: String!
}
input UserChangesInput implements UserInputInterface {
id: ID!
password: String
}
不,规范不允许输入类型实现接口。并且 GraphQL 类型系统通常不定义任何形式的继承(extends
关键字将字段添加到现有类型,而不是用于继承)。该规范有意限制为保持简单。这意味着您无法跨输入类型重复字段。
就是说,根据您构建模式的方式,您可以构建某种类型的转换器,它基于某些元数据以编程方式附加公共字段,例如指令。
更好的是,您可以通过组合来解决您的问题(请始终牢记 composition over inheritance)。
例如
input Name {
firstName: String
lastName: String
}
input UserInput {
name: Name
password: String!
}
input UserChangesInput {
name: Name
id: ID!
password: String
}
客户端现在必须将对象发送到更深的层次,但这听起来不像是避免大的重复块的代价。这实际上可能对客户也有好处,因为他们现在可以拥有构建名称的通用逻辑,而不管 query/mutation 使用它们。
在这个例子中,它只有 2 个简单的字段,这种方法有点矫枉过正,但总的来说 - 我认为这是可行的方法。
从 June2018 stable version of the GraphQL spec 开始,输入对象类型可以扩展 另一个输入对象类型:
Input object type extensions are used to represent an input object type which has been extended from some original input object type.
这本身不是继承;您只能扩展基本类型,不能基于它创建新类型:
extend input MyInput {
NewField: String
}
请注意,新类型没有名称;现有 MyInput
类型已扩展。
JavaScript 参考实现 implemented Input Object extensions in GraphQL.js v14 (June 2018), though it's unclear how to actually pass the extended input fields to a query 没有出现错误。
有关实际类型继承,请参阅 graphql-s2s library。
如果您是来这里寻找“implements”关键字的解释,这里是:
An object type must be a super‐set of all interfaces it implements. The object type must include a field of the same name for every field defined in an interface.
(摘自 June 2018 GraphQL spec。)
举个例子
interface Foo {
id: ID!
foo: Int!
}
type Bar implements Foo @entity {
id: ID!;
foo: Int!;
bar: Int!;
}
因此 Bar
类型不 继承 来自 Foo
接口,但它 实现 它.前者必须包括后者列出的所有字段。
我认为这是一种注释类型的好方法,这些类型应该与其他类型相同。
使用自定义指令是可行的。
代码摘要
const typeDefs = gql`
directive @inherits(type: String!) on OBJECT
type Car {
manufacturer: String
color: String
}
type Tesla @inherits(type: "Car") {
manufacturer: String
papa: String
model: String
}
type Query {
tesla: Tesla
}
`;
const resolvers = {
Query: {
tesla: () => ({ model: 'S' }),
},
Car: {
manufacturer: () => 'Ford',
color: () => 'Orange',
},
Tesla: {
manufacturer: () => 'Tesla, Inc',
papa: () => 'Elon',
},
};
class InheritsDirective extends SchemaDirectiveVisitor {
visitObject(type) {
const fields = type.getFields();
const baseType = this.schema.getTypeMap()[this.args.type];
Object.entries(baseType.getFields()).forEach(([name, field]) => {
if (fields[name] === undefined) {
fields[name] = { ...field };
}
});
}
}
const schemaDirectives = {
inherits: InheritsDirective,
};
查询:
query {
tesla {
manufacturer
papa
color
model
}
}
输出:
{
"data": {
"tesla": {
"manufacturer": "Tesla, Inc",
"papa": "Elon",
"color": "Orange",
"model": "S",
}
}
}
是否可以对 GraphQL 输入类型使用继承?
类似的东西(当然,这不适用于输入类型):
interface UserInputInterface {
firstName: String
lastName: String
}
input UserInput implements UserInputInterface {
password: String!
}
input UserChangesInput implements UserInputInterface {
id: ID!
password: String
}
不,规范不允许输入类型实现接口。并且 GraphQL 类型系统通常不定义任何形式的继承(extends
关键字将字段添加到现有类型,而不是用于继承)。该规范有意限制为保持简单。这意味着您无法跨输入类型重复字段。
就是说,根据您构建模式的方式,您可以构建某种类型的转换器,它基于某些元数据以编程方式附加公共字段,例如指令。
更好的是,您可以通过组合来解决您的问题(请始终牢记 composition over inheritance)。 例如
input Name {
firstName: String
lastName: String
}
input UserInput {
name: Name
password: String!
}
input UserChangesInput {
name: Name
id: ID!
password: String
}
客户端现在必须将对象发送到更深的层次,但这听起来不像是避免大的重复块的代价。这实际上可能对客户也有好处,因为他们现在可以拥有构建名称的通用逻辑,而不管 query/mutation 使用它们。
在这个例子中,它只有 2 个简单的字段,这种方法有点矫枉过正,但总的来说 - 我认为这是可行的方法。
从 June2018 stable version of the GraphQL spec 开始,输入对象类型可以扩展 另一个输入对象类型:
Input object type extensions are used to represent an input object type which has been extended from some original input object type.
这本身不是继承;您只能扩展基本类型,不能基于它创建新类型:
extend input MyInput {
NewField: String
}
请注意,新类型没有名称;现有 MyInput
类型已扩展。
JavaScript 参考实现 implemented Input Object extensions in GraphQL.js v14 (June 2018), though it's unclear how to actually pass the extended input fields to a query 没有出现错误。
有关实际类型继承,请参阅 graphql-s2s library。
如果您是来这里寻找“implements”关键字的解释,这里是:
An object type must be a super‐set of all interfaces it implements. The object type must include a field of the same name for every field defined in an interface.
(摘自 June 2018 GraphQL spec。)
举个例子
interface Foo {
id: ID!
foo: Int!
}
type Bar implements Foo @entity {
id: ID!;
foo: Int!;
bar: Int!;
}
因此 Bar
类型不 继承 来自 Foo
接口,但它 实现 它.前者必须包括后者列出的所有字段。
我认为这是一种注释类型的好方法,这些类型应该与其他类型相同。
使用自定义指令是可行的。
代码摘要
const typeDefs = gql`
directive @inherits(type: String!) on OBJECT
type Car {
manufacturer: String
color: String
}
type Tesla @inherits(type: "Car") {
manufacturer: String
papa: String
model: String
}
type Query {
tesla: Tesla
}
`;
const resolvers = {
Query: {
tesla: () => ({ model: 'S' }),
},
Car: {
manufacturer: () => 'Ford',
color: () => 'Orange',
},
Tesla: {
manufacturer: () => 'Tesla, Inc',
papa: () => 'Elon',
},
};
class InheritsDirective extends SchemaDirectiveVisitor {
visitObject(type) {
const fields = type.getFields();
const baseType = this.schema.getTypeMap()[this.args.type];
Object.entries(baseType.getFields()).forEach(([name, field]) => {
if (fields[name] === undefined) {
fields[name] = { ...field };
}
});
}
}
const schemaDirectives = {
inherits: InheritsDirective,
};
查询:
query {
tesla {
manufacturer
papa
color
model
}
}
输出:
{
"data": {
"tesla": {
"manufacturer": "Tesla, Inc",
"papa": "Elon",
"color": "Orange",
"model": "S",
}
}
}