GraphQL 是一种用于 API 的查询语言,允许客户端对服务器进行精确的数据查询。分页查询是查询大量数据时常用的技术方案,然而在 GraphQL 中,分页查询并不像传统的 REST API 那样简单直接。本文将详细介绍如何在 GraphQL 中实现分页查询,并通过示例代码指导读者进行实践。
传统 REST API 中的分页查询
在传统 REST API 的设计中,分页查询通常使用 limit 和 offset 两个参数来决定需要返回的结果数量和起始位置。
例如,以下查询可以返回 users
表中第 11 条到第 20 条的用户数据:
// GET /users?limit=10&offset=10 [ { "id": 11, "name": "User 11", ... }, ... { "id": 20, "name": "User 20", ... } ]
然而,在 GraphQL 中,这种简单的查询方式无法实现,我们需要使用其他方法来实现分页查询。
GraphQL 中的分页查询问题
在 GraphQL 中,每次查询返回的数据结构是预先定义好的,我们需要为每个数据类型定义查询字段。通常情况下,我们无法使用类似于 limit 和 offset 的参数来直接决定查询结果的数量和起始位置,而是需要定义一个表示分页的新类型来解决这个问题。
GraphQL 中通常使用一个名为 PageInfo
的新类型来表示分页,该类型包含一些元数据信息,例如是否有更多数据、当前页数等。此外,我们还需要定义一个新的查询节点来返回一个带有 PageInfo
的结果集。下面是一个 PageInfo
的定义示例:
type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String }
基于上文中的问题描述和解决方案,我们可以在 GraphQL 中使用以下方案来实现分页查询:
- 定义一个查询节点,该节点返回一个带有
PageInfo
的结果集。
type Query { users(first: Int, after: String): UserConnection! }
其中 first
参数为请求的数量,after
参数为查询的起始游标。UserConnection
是一个自定义的新类型,表示在当前节点下的连接。
- 定义
UserConnection
类型,该类型包含edges
和pageInfo
两个字段。
type UserConnection { edges: [UserEdge!]! pageInfo: PageInfo! }
edges
字段包含一个含有 User
对象的数组,pageInfo
字段则包含一个表示分页信息的 PageInfo
类型。
- 定义
UserEdge
类型,该类型包含一个node
字段和一个cursor
字段。
type UserEdge { node: User! cursor: String! }
node
字段表示每个用户对象,cursor
字段则是一个表示该对象的游标字符串。
- 在查询节点中执行数据查询,并使用
UserConnection
类型封装结果。
const users = [ { id: "1", name: "User 1" }, { id: "2", name: "User 2" }, { id: "3", name: "User 3" }, { id: "4", name: "User 4" }, { id: "5", name: "User 5" }, { id: "6", name: "User 6" }, { id: "7", name: "User 7" }, { id: "8", name: "User 8" }, { id: "9", name: "User 9" }, { id: "10", name: "User 10" }, { id: "11", name: "User 11" }, { id: "12", name: "User 12" }, { id: "13", name: "User 13" }, { id: "14", name: "User 14" }, { id: "15", name: "User 15" } ]; const query = { users: (_, args) => { const results = users.slice(args.after || 0, args.first + (args.after || 0)); const edges = results.map((user, index) => ({ cursor: args.after ? parseInt(args.after, 10) + index + 1 : index + 1, node: user })); return { edges, pageInfo: { hasNextPage: results.length + (args.after || 0) < users.length, hasPreviousPage: !!args.after, startCursor: edges.length > 0 ? edges[0].cursor.toString() : "", endCursor: edges.length > 0 ? edges[edges.length - 1].cursor.toString() : "" } }; } };
示例代码中实现的是一个获取用户列表的查询节点,请求参数为 first
和 after
,并使用 UserConnection
封装结果。const users
为一个包含 15 个用户信息的数组。
最后,我们可以使用以下查询来获取用户列表的第 2 到第 6 条数据:
query Users { users(first: 5, after: 1) { edges { cursor node { id name } } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } }
该查询返回的结果如下:
{ "data": { "users": { "edges": [ { "cursor": "2", "node": { "id": "2", "name": "User 2" } }, { "cursor": "3", "node": { "id": "3", "name": "User 3" } }, { "cursor": "4", "node": { "id": "4", "name": "User 4" } }, { "cursor": "5", "node": { "id": "5", "name": "User 5" } }, { "cursor": "6", "node": { "id": "6", "name": "User 6" } } ], "pageInfo": { "hasNextPage": true, "hasPreviousPage": true, "startCursor": "2", "endCursor": "6" } } } }
总结
本文详细介绍了 GraphQL 中的分页查询问题和解决方案,并通过示例代码演示了如何在 GraphQL 中实现分页查询。正如我们在示例代码中看到的那样,GraphQL 中的分页查询确实要比传统 REST API 中的分页查询更复杂,但是我们可以通过创建新的分页类型和查询节点来克服这些问题。如果你正在使用 GraphQL 作为你的 API 工具,那么掌握分页查询是非常重要的,本文希望能够对你有所帮助。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a2004fadd4f0e0ffa13712