与我们在 10 月 8-10 日在纽约市相聚,了解关于 GraphQL 联邦和 API 平台工程的最新技巧、趋势和新闻。加入我们出席 2024 年纽约市的 GraphQL Summit
文档
免费开始

GraphQL接口推荐的用法

探索示例,避免常见陷阱

模式设计联盟

💡 技巧

如果您是企业客户,想了解更多关于这个主题的内容,尝试企业最佳实践:模式设计的课程.

不是企业客户? 了解GraphOS企业版。

接口允许模式返回多个之一,所有这些类型都必须实现该接口。为了实现接口,对象类型必须定义接口中包含的所有字段(否则,模式无效):

interface Media {
title: String!
}
type Book implements Media {
title: String!
author: String!
}

因为接口可以在实现 对象类型上强制执行此要求,所以纯粹为了强制定义来创建接口是很有诱惑力的。下面的方案要求所有的对象类型都通过声明这些类型实现 Nameable 接口来声明 name 字段:name 字段在其所有对象类型中通过声明这些类型实现 Nameable 接口来声明:

interface Nameable {
name: String
}
type Cat implements Nameable {
name: String
meowVolume: Int
}
type Dog implements Nameable {
name: String
barkVolume: Int
}
type Owner implements Nameable {
name: String
cats: [Cat]
dogs: [Dog]
}
type Query {
owners: [Owner]
}

⚠️ 注意

这不是接口推荐的使用方式!注意,在这个方案中,Nameable 永远没有被用作字段的返回类型。这意味着客户端没有方法利用这种多态关系执行

有效客户端用例的缺乏暗示了一种代码问题。Nameable 接口是不必要的,而且它可能会在你的方案在未来更改时引起问题。 分配它自己的挑战,所以去除不必要的接口通常会使流程变得更简单。

在下一个示例中,我们指定CatDog 类型实现 Pet 接口,以便我们可以在 Owner.pets 字段中返回两种类型的 Fat 和 Dog 的聚合列表。现在存在一个有效的客户端用例进行多态,使用接口是合理的。

interface Pet {
name: String
}
type Cat implements Pet {
name: String
meowVolume: Int
}
type Dog implements Pet {
name: String
barkVolume: Int
}
type Owner {
name: String
pets: [Pet]
}
type Query {
owners: [Owner]
}

添加新实现类型的影响

当客户端在 操作 中包含返回抽象类型的字段时,他们通常会使用 "条件 ," 列举他们感兴趣的来自具体类型的字段,如下所示:

query OwnersAndPets {
owners {
name
pets {
name
... on Cat {
meowVolume
}
... on Dog {
barkVolume
}
}
}
}

注意

如果Pet是一个联合体而不是接口(union Pet = Cat | Dog),则所有请求的字段都需要包含在条件片段中。即使在两种类型都定义了该字段的情况下,也无法在name字段外包含它。

如果您的API为抽象类型添加了额外的可能类型,则客户端必须更改其操作以从这些新类型中选择数据。虽然这不是一个破坏性的更改,但这种情况下需要一些防御性编程。

// Trigger a TypeScript error if a new type is introduced but
// we haven't added a switch case for it.
const assertUnknown = (x: never) =>
console.log(`Unknown Pet type: ${(x as any).__typename}`);
switch (pet.__typename) {
case 'Cat':
console.log(`Cat meows ${pet.meowVolume}`);
break;
case 'Dog':
console.log(`Dog barks ${pet.barkVolume}`);
break;
default:
assertUnknown(pet);
console.log('Fallback behavior');
}

注意

当使用 graphql-code-generator时,访问已知的接口字段,如Pet.name将触发TypeScript错误。请参阅问题8538以获取更多信息。

// `when` must be used as an expression to require exhaustivity
val result = when (pet.__typename) {
"Cat" -> println("Cat meows ${pet.onCat?.meowVolume}")
"Dog" -> println("Dog barks ${pet.onDog?.barkVolume}")
else -> println("Unknown animal ${pet.__typename}")
}
switch pet.__typename {
case "Cat":
print("Cat meows \(pet.asCat?.meowVolume ?? 0)")
case "Dog":
print("Dog barks \(pet.asDog?.barkVolume ?? 0)")
default:
print("Unknown animal \(pet.__typename)")
}
下一步
首页
评价文章评价在GitHub上编辑编辑论坛Discord

©2024Apache Graph Inc.,即Apollo GraphQL。

隐私策略

公司