如何在 GraphQL 中继承或扩展 typeDef
How to Inherit or Extend typeDefs in GraphQL
我有一个type User
。用户也可以是type TeamMember
。 User
和 TeamMember
之间的唯一区别是添加了字段 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;
}
});
}
}
我有一个type User
。用户也可以是type TeamMember
。 User
和 TeamMember
之间的唯一区别是添加了字段 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;
}
});
}
}