如何在GraphQL中继承或扩展typeDefs

23

我有一个用户类型。用户还可以是团队成员类型用户团队成员之间唯一的区别是增加了一个字段teamRole:字符串。因此,我想做以下类似的事情,以避免不必要地定义所有用户字段...

  type User {
    id: ID!,
    name: String,
    (many other field defs)
  }

  type TeamMember extends User  {
    teamRole: String,
  }

有人知道这个的语法吗?我原以为extend会是答案,但它看起来更像JavaScript中的prototype

2个回答

18
extend 关键字非常适用于你拥有一个基础架构并想要构建两个或更多可用架构的情况。例如,您可以定义一个根 Query 类型,其中包含所有架构共享的查询,然后在每个单独的架构中扩展它以添加特定于该架构的查询。它还可用于模块化架构。但需要注意的是,它仅是向现有类型添加功能的机制,不能用于创建新类型。
GraphQL本身不支持继承。没有语法可以帮助您避免在多个类型之间复制字段。
您可以利用字符串插值来避免一遍又一遍地输入相同的字段:
const sharedFields = `
  foo: String
  bar: String
`
const typeDefs = `
  type A {
    ${sharedFields}
  }

  type B {
    ${sharedFields}
  }
`

除此之外,您还可以使用像graphql-s2s这样的库,它允许您利用继承和泛型类型。通过这种方式生成的模式仍然必须编译为有效的SDL -- 最好的情况下,像graphql-s2s这样的库只提供了一些语法糖和更好的开发体验。

最后,您可以重构您的类型以避免完全重复字段,但代价是响应结构更加结构化。例如,不要这样做:

type A {
  a: Int
  foo: String
  bar: String
}

type B {
  b: Int
  foo: String
  bar: String
}

你可以这样做:

type X {
  foo: String
  bar: String
  aOrB: AOrB
}

union AOrB = A | B

type A {
  a: Int
}

type B {
  b: Int
}

谢谢!这正是我在寻找的。嗯,不完全是,因为理想情况下我不需要另一个包,但graphql-s2s给了我我所需要的。我正在使用graphql-yoga作为我的服务器,所以我必须monkey patch their typeDefs声明,这也不是最理想的方式。如果你知道更好的方法,我会听取意见的。谢谢! - Chris Geirman
截至2019年中,这仍然不可用,这是真的吗? - A.com
@A.com 是的。您可以在此处查看最新规范(https://graphql.github.io/graphql-spec/)。 - Daniel Rearden
但是早在2020年初,您不会使用@inherit from吗? - Alexander
1
@Alexander,那不是标准指令--它使用的是哪个库? - Daniel Rearden
1
当我使用谷歌搜索确切短语“@inherit from”时,这个堆栈溢出的问题是唯一显示的页面。你发明了一个全新的句子。 - flodin

2
使用像graphql-s2s这样的模式转换器来实现继承可能有些过度,而且graphql-s2s在2021年已经过时了。
可以看一下这个Apollo Server指令:https://github.com/jeanbmar/graphql-inherits
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
  }
`;

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;
            }
        });
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接