GraphQL 是一种新兴的 API 查询语言,它与传统的 RESTful API 不同,它可以更精确和灵活地查询和获取数据。在 GraphQL 中,分页查询是非常常见的需求,本文将介绍 GraphQL 中的分页查询实现方式。
传统的分页查询
在传统的 RESTful API 中,分页查询通常是通过 limit 和 offset 参数来实现的,例如:
GET /users?limit=10&offset=20
这个请求将返回第 21-30 条用户记录。这种方式虽然简单,但它存在一些问题:
- 如果数据量非常大,那么每次查询都需要返回全部数据,这会导致网络带宽和服务器资源的浪费。
- 如果数据量非常小,那么每次查询都需要返回全部数据,这会导致网络带宽和服务器资源的浪费。
GraphQL 中的分页查询
在 GraphQL 中,分页查询可以通过 first 和 after 参数来实现,例如:
// www.javascriptcn.com code example
query {
allUsers(first: 10, after: "20") {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}这个查询将返回第 21-30 条用户记录,其中 first 参数表示要返回的记录数,after 参数表示从哪个游标开始查询。返回的结果包含一个 edges 数组和一个 pageInfo 对象。edges 数组包含了每条记录及其游标,pageInfo 对象包含了分页信息,例如是否有下一页,是否有上一页,起始游标和结束游标等。
实现方式
在 GraphQL 中,分页查询的实现方式通常有两种:
基于游标的分页
基于游标的分页是一种常见的分页方式,它可以避免传统的分页查询中的问题。在 GraphQL 中,基于游标的分页可以通过 cursor 字段来实现,例如:
// www.javascriptcn.com code example
query {
allUsers(first: 10, after: "20") {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}这个查询将返回第 21-30 条用户记录,其中 after 参数指定了从哪个游标开始查询,edges 数组中的每个元素都包含了一个 cursor 字段,表示该记录的游标。pageInfo 对象中的 startCursor 和 endCursor 字段分别表示了当前页的起始游标和结束游标。
基于页码的分页
基于页码的分页是另一种常见的分页方式,它可以更直观地展示当前页的位置和总页数。在 GraphQL 中,基于页码的分页可以通过 page 和 perPage 参数来实现,例如:
// www.javascriptcn.com code example
query {
allUsers(page: 3, perPage: 10) {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
totalPages
currentPage
perPage
totalCount
}
}
}这个查询将返回第 21-30 条用户记录,其中 page 参数指定了当前页码,perPage 参数指定了每页返回的记录数。pageInfo 对象中的 totalPages 和 currentPage 字段分别表示了总页数和当前页码,perPage 字段表示了每页返回的记录数,totalCount 字段表示了总记录数。
示例代码
以下是一个使用基于游标的分页查询的示例代码:
// www.javascriptcn.com code example
const { ApolloServer, gql } = require("apollo-server");
const typeDefs = gql`
type User {
id: ID!
name: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String!
endCursor: String!
}
type UsersConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
}
type UserEdge {
cursor: String!
node: User!
}
type Query {
allUsers(first: Int, after: String): UsersConnection!
}
`;
const users = [
{ id: "1", name: "Alice" },
{ id: "2", name: "Bob" },
{ id: "3", name: "Charlie" },
{ id: "4", name: "David" },
{ id: "5", name: "Eve" },
{ id: "6", name: "Frank" },
{ id: "7", name: "Grace" },
{ id: "8", name: "Hank" },
{ id: "9", name: "Ivy" },
{ id: "10", name: "Jack" },
{ id: "11", name: "Kate" },
{ id: "12", name: "Lily" },
{ id: "13", name: "Mike" },
{ id: "14", name: "Nancy" },
{ id: "15", name: "Oliver" },
{ id: "16", name: "Peter" },
{ id: "17", name: "Queen" },
{ id: "18", name: "Rose" },
{ id: "19", name: "Sam" },
{ id: "20", name: "Tom" },
];
const resolvers = {
Query: {
allUsers: (_, { first = 10, after }) => {
const startIndex = after ? users.findIndex((user) => user.id === after) + 1 : 0;
const endIndex = startIndex + first;
const edges = users.slice(startIndex, endIndex).map((user) => ({ cursor: user.id, node: user }));
const startCursor = edges.length > 0 ? edges[0].cursor : null;
const endCursor = edges.length > 0 ? edges[edges.length - 1].cursor : null;
const hasNextPage = endIndex < users.length;
const hasPreviousPage = startIndex > 0;
return {
edges,
pageInfo: {
startCursor,
endCursor,
hasNextPage,
hasPreviousPage,
},
};
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});这个示例代码中定义了一个 User 类型和一个 UsersConnection 类型,UserEdge 类型表示了一个带游标的用户记录。allUsers 查询接受一个 first 参数和一个 after 参数,返回一个 UsersConnection 对象,其中 edges 数组包含了每个带游标的用户记录,pageInfo 对象包含了分页信息。查询时,根据 after 参数来确定起始游标,并根据 first 参数来确定返回的记录数,最后根据返回的记录数来确定结束游标和是否有下一页。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d29b9ca941bf71344fd2f2