关系式连接和分页常见问题问答
关于Relay的连接规范的常见问题
Relay 是一种有意见的 GraphQL客户端,以及其相关的 连接规范 定义了在 GraphQL模式 中表达一对一关系的模式:
query MyPosts($cursor: String) {viewer {posts(first: 5, after: $cursor) {edges {node {idtitlecontent}cursor}pageInfo {hasNextPageendCursor}}}}
值得注意的是,Facebook 在设计其新闻源功能时,考虑到这些特性,并为他们的新闻源功能设计了 Connections 规范
- 它使用 光标-基于的分页。
- 它支持向后(使用
before
光标)和向前(使用after
光标)分页。 - 列表中的每个条目都有一个 光标,您可以使用它跳转到列表中间的特定页面。
这些功能可能不完全满足您的需求或下游 数据源的功能。
我必须使用 Relay 风格的连接吗?
不需要,除非您正在使用 Relay 客户端。但它的流行度值得您在 Relay 生态系统之外加以利用
- 许多开发者熟悉连接模式。
- 它封装了几个架构设计最佳实践。
- 它旨在实现向后兼容并支持您 GraphQL 架构的逐步演化。
我甚至需要为我的列表创建一个包装器类型吗?
考虑 "零,一,无穷"规则——您能否断言您的列表永远不需要分页或其他关于关系的元数据?
使用列表包装器类型具有以下优点
避免破坏性更改:您最初可以返回一个不使用分页的包装器类型,然后在不破坏现有客户端的情况下添加分页。如果您直接返回列表,则无法稍后添加分页元数据。
代表 实体 关联:连接
Connection
和 边Edge
包装类型支持 字段,用于表示不属于实体的实体间属性。考虑这样一个例子:一个多对多的业务
Business
和 客户Customer
之间的关系:type Business {id: IDcustomers: CustomerConnection}type CustomerConnection {edges: [CustomerEdge]total: Int}type CustomerEdge {node: Customertype: CustomerType}enum CustomerType {IN_STOREONLINEMULTI_CHANNEL}type Customer {id: IDshopsAt: BusinessConnection # --snip --}一个特定的
Customer
可能在一个IN_STORE
商店和一个ONLINE
网上商店购物。type
是关系的属性,而不是业务或客户自身的属性。没有包装类型,就没有地方放置这些数据。
我必须实现整个连接规范吗?
不,您可以使用规范的一部分。您可以在需要时逐步实现额外的部分以达到规范要求的完整兼容性。
如果您的下游数据源不支持向后分页,您可以将实现限制为正向分页:
如果您的下游数据源不支持每个节点的 游标,您可以删除 edges
字段 并使用 nodes
:
还有其他设计分页方案的方法吗?
是的。如果您的需求或下游能力不适合Relay风格的连接规范,我们建议使用一组明显不同的约定,以便于图消费者明确知道他们不应该期望使用Relay连接模式。
这是一个使用页偏移并支持跳转到特定页面的分页示例
我可以在Apollo Federation中使用Relay-style连接吗?
是的!您可以定义单个子图中连接关系的模式和解析器,因此联邦对该模式的副作用几乎可以忽略不计。
唯一例外是 PageInfo
类型,这对于所有连接通常有一个一致的定义。您必须将此类型的定义标记为 @shareable
,以便在多个 子图中定义:
type PageInfo @shareable {hasNextPage: Boolean!hasPreviousPage: Boolean!startCursor: StringendCursor: String}