GraphQL输入类型可以继承自另一个类型或接口吗?

时间:2017-01-29 12:57:11

标签: graphql

是否可以将继承与GraphQL输入类型一起使用?

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

interface UserInputInterface {
  firstName: String
  lastName: String
}

input UserInput implements UserInputInterface {
  password: String!
}

input UserChangesInput implements UserInputInterface {
  id: ID!
  password: String
}

4 个答案:

答案 0 :(得分:13)

不,规范不允许输入类型实现接口。而GraphQL类型系统一般不定义任何形式的继承。甚至接口也不能继承其他接口。故意限制规范以保持简单。这意味着你不得不在输入类型中重复字段。

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

更好的是,您可以通过合成来解决您的问题。 E.g。

input Name {
  firstName: String
  lastName: String
}

input UserInput {
  name: Name
  password: String!
}

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

客户端现在必须向对象发送更深层次的对象,但这听起来并不是避免大量重复块的代价。它实际上对客户端也有好处,因为它们现在可以具有用于构建名称的通用逻辑,而不管使用它们的查询/变异。

在这个例子中,它只有两个简单的字段,这种方法是一种矫枉过正,但总的来说 - 我会说这是一种方法。

答案 1 :(得分:1)

June2018 stable version of the GraphQL spec开始,输入对象类型可以扩展另一种输入对象类型:

  

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

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

extend input MyInput {
  NewField: String
}

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

JavaScript参考实现在implemented Input Object extensions中有GraphQL.js v14(2018年6月),尽管目前尚不清楚如何在没有错误的情况下实际pass the extended input fields to a query

有关实际类型继承,请参见graphql-s2s library

答案 2 :(得分:0)

如果您是来这里寻找“实现”关键字的说明的,则为:

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

(摘录自June 2018 GraphQL spec。)

这是一个例子


interface Foo {
  id: ID!
  foo: Int!
}

type Bar implements Foo @entity {
  id: ID!;
  foo: Int!;
  bar: Int!;
}

因此,Bar类型不是从Foo接口中继承(emheriting),而是实现。前者必须包括后者中列出的所有字段。

我认为这是注释与其他类型相似的类型的好方法。

答案 3 :(得分:0)

使用自定义指令是可行的。

代码摘要

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 的工作示例。