GraphQL 输入类型可以从其他类型或接口继承吗?

是否可以对 GraphQL 输入类型使用继承?

类似的东西(当然,这个不适用于输入类型) :

interface UserInputInterface {
firstName: String
lastName: String
}


input UserInput implements UserInputInterface {
password: String!
}


input UserChangesInput implements UserInputInterface {
id: ID!
password: String
}
45903 次浏览

不,规范不允许输入类型实现接口。GraphQL 类型系统通常不定义任何形式的继承(extends关键字将字段添加到现有类型,并且不用于继承)。规范被有意地限制为保持简单。这意味着您必须在输入类型之间重复输入字段。

也就是说,根据您构建模式的方式,您可以构建某种类型转换器,它基于某些元数据(例如指令)以编程方式附加公共字段。

更好的是,你也许能够通过组合来解决你的问题(始终记住 继承上的组合)。 例如。

input Name {
firstName: String
lastName: String
}


input UserInput {
name: Name
password: String!
}


input UserChangesInput {
name: Name
id: ID!
password: String
}

客户机现在必须将对象发送到更深的级别,但是这听起来不像是避免大的重复块的代价。这实际上可能对客户机也有好处,因为它们现在可以拥有构建名称的公共逻辑,而不用考虑使用它们的查询/变异。

在这个例子中,只有两个简单的字段,这种方法有点过了,但是总的来说——我认为这是正确的方法。

GraphQL 规范的稳定版本开始,一个 Input Object 类型可以 延伸另一个 Input Object 类型:

输入对象类型扩展用于表示从某个原始输入对象类型扩展而来的输入对象类型。

这不是继承本身; 您只能扩展基类型,而不能基于它创建新类型:

extend input MyInput {
NewField: String
}

注意,没有新类型的名称; 现有的 MyInput类型是扩展的。

JavaScript 引用实现在 GraphQL.js v14中包含了 实现的输入对象扩展(2018年6月) ,尽管还不清楚如何实际执行 将扩展的输入字段传递给查询而不出现错误。

有关实际的类型继承,请参见 Graphql-s2s 库

如果你来这里是为了解释“工具”,关键字,这里是:

对象类型必须是它实现的所有接口的超集。对象类型必须包含接口中定义的每个字段的相同名称的字段。

(节录自 2018年6月 GraphQL 规范。)

举个例子


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",
}
}
}

https://github.com/jeanbmar/graphql-inherits的工作示例。