如何在 GraphQL 中继承或扩展 typeDef

How to Inherit or Extend typeDefs in GraphQL

我有一个type User。用户也可以是type TeamMemberUserTeamMember 之间的唯一区别是添加了字段 teamRole: String。所以,我很想做类似下面的事情,以避免必须冗余定义所有用户的字段......

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

  type TeamMember extends User  {
    teamRole: String,
  }

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

如果您有基本模式并希望基于它构建两个或更多可用模式,则 extend 关键字非常有用。例如,您可以定义一个根 Query 类型,其中包含所有模式共享的查询,然后在每个单独的模式中扩展它以添加特定于该模式的查询。它还可以用于模块化模式。但是,它只是一种向现有类型添加功能的机制 -- 它不能用于创建新类型。

GraphQL 本身并不支持继承。没有语法可以帮助您避免跨多种类型的字段重复。

您可以利用字符串插值来避免重复输入相同的字段:

const sharedFields = `
  foo: String
  bar: String
`
const typeDefs = `
  type A {
    ${sharedFields}
  }

  type B {
    ${sharedFields}
  }
`

除此之外,您还可以使用像 graphql-s2s 这样的库,它允许您使用继承和泛型类型。以这种方式生成的模式仍然必须编译为有效的 SDL——充其量,像 graphql-s2s 这样的库只是提供一些语法糖和更好的 DX。

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

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-s2s 到 2021 年就已经过时了。

看看这个 Apollo 服务器指令: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;
            }
        });
    }
}