This repository offers utilities and tools to streamline efficient pagination of GraphQL queries in applications using the GitHub API. It simplifies the management of paginated results and provides a ready-to-use solution for your GraphQL-based projects interacting with API data.
- Open the repository where you want to install the library
- Run this command in a command console:
npm install gql-paginator
- Import the library in the js file in which you want to use the functions:
const { GQLPaginator } = require('gql-paginator');
This async function receives a query, a token, and a configuration, and returns the paginated result if possible or the non-paged result if not. Result's examples
result = await GQLPaginator(query, token, configuration);
Parameters:
- Query: Add the query you need to paginate, and put it in quotes. Remember that to paginate you need to build a query that provides the information necessary to do so. How to build a valid query for pagination?
- Token: Your API token in quotes. You can find more information on how to generate a token on the page of the API you are using.
-
Configuration: The required pagination configuration of the API in use. You can also create your own configuration or modify existing ones by following the configuration creation and editing guide. Default configurations:
- github-v1.0.0
- zenhub-v1.0.0
In order for pagination to be carried out, it is necessary to follow a series of rules when building the query (example), which are listed below:
- All pageable types must contains:
nodes {
id
}
pageInfo {
hasNextPage
endCursor
}
totalCount
- Query mustn't contains:
- after
The configuration chosen when calling the GQLPaginator function defines certain parameters that are necessary to know in order to paginate a result. This is due to the variability of GraphQL when generating subqueries. This section explains how to modify existing configurations or create a new one for an unsupported API.
(This requires studying how the GraphQL API you are using works)
- Go to your repository from opening the path node_modules/gql-paginator/configurations/sources
- Create a new configuration called: "api-name"-v1.0.0.json
- Use this template to create a new API configuration
{
"id": "",
"url": "",
"complexSubqueryPath": ,
"firstLevelPtype": [],
"paths":{
}
}
- Fill out all the fields following the explanation below (It's recommended to compare what you fill in with the default configurations):
- id: "api-name"-v1.0.0
- url: api url.
- complexSubqueryPath: if the subquery of your api is made following the github (PullRequestReview) structure then true, if they are made like zenhub (only Review) then false.
- firstLevelPtype: if complexSubqueryPath is true then fill the array with only first level types.
- paths: the paths of your query with the necessary value to generate a correct subquery.
If you are using an existing configuration and you call the function with the correct parameters, but the configuration does not include the pageable object that you want to page, it will let you know through the logs in the console and describe the paths that you should add.
Example:
I have this github-v1.0.0 configuration:
{
"id": "github-v1.0.0",
"url": "https://api.github.com/graphql",
"complexSubqueryPath": true,
"firstLevelPtype": ["pullRequests","issues"],
"paths":{
"pullRequests.*": "PullRequest",
"issues.*": "Issue"
}
}
When I try to paginate my github query that you can find in the examples, the console will return this error:
Solution: add the path in the specified json
{
"id": "github-v1.0.0",
"url": "https://api.github.com/graphql",
"complexSubqueryPath": true,
"firstLevelPtype": ["pullRequests","issues"],
"paths":{
"pullRequests.*": "PullRequest",
"issues.*": "Issue",
"pullRequests.reviews.*": "PullRequestReview"
}
}
Change ${repository-name} and ${user-name} to the repository name that you are using and your user name. Change ${token} to your github token.
GQLPaginator(`{
repository(name: "${repository-name}", owner:"${user-name}") {
issues(first: 1) {
totalCount
pageInfo {
hasNextPage
endCursor
}
nodes {
id
title
}
}
pullRequests(first: 1) {
totalCount
pageInfo {
endCursor
}
nodes {
id
state
title
body
baseRefName
headRefName
createdAt
author {
login
}
mergedAt
mergedBy {
login
}
reviews(first: 1) {
totalCount
pageInfo {
hasNextPage
endCursor
}
nodes {
id
createdAt
state
reactions (first: 1) {
totalCount
pageInfo {
hasNextPage
endCursor
}
nodes {
content
id
user{
name
}
}
}
}
}
assignees(first: 1){
pageInfo {
hasNextPage
endCursor
}
totalCount
nodes{
id
name
}
}
}
}
}
}`, ${token}, 'github-v1.0.0')
If you look at the query, pullRequests (paginable type) does not have the hasNextPage attribute within pageInfo, which was a mandatory requirement to be able to paginate. Therefore, pullRequests will not be paged, but the rest of the pageable types will be. You can add hasNextPage attribute and you'll see how now the pagination is done in pullRequests.
Obtained result:
{
"data": {
"repository": {
"issues": {
"totalCount": 52,
"pageInfo": {
"hasNextPage": true,
"endCursor": "Y3Vyc29yOnYyOpHOYHBmyA=="
},
"nodes": [
{
"id": "I_kwDOI8VKA85e5OIH",
"title": "Task #2.6 Technical report and task diagram"
},
{
"id": "I_kwDOI8VKA85e5O3A",
"title": "Task #2.7 Methodologies management report"
},
{
"id": "I_kwDOI8VKA85e5QOJ",
"title": "Task #2.8 a) Pet hotel functionality"
},
{
"id": "I_kwDOI8VKA85e5Qt7",
"title": "Task #2.8 b) Web style"
},
{
"id": "I_kwDOI8VKA85e5RDZ",
"title": "Task #2.8 c) Add and edit veterinarians"
},
...
Change ${repository-id} to the repository name that you can find it in your board url:
Change ${token} to your zenhub token.
GQLPaginator(`query {
workspace(id: "${repository-id}") {
repositoriesConnection(first: 10) {
nodes {
id
ghId
name
issues(first:5){
pageInfo{
hasNextPage
endCursor
}
totalCount
nodes{
id
title
timelineItems(first:10){
pageInfo{
hasNextPage
endCursor
}
totalCount
nodes{
id
data
key
updatedAt
}
}
}
}
owner {
login
}
}
}
}
}`, ${token}, 'zenhub-v1.0.0')
Obtained result:
{
"data": {
"workspace": {
"repositoriesConnection": {
"nodes": [
{
"id": "Z2lkOi8vcmFwdG9yL1JlcG9zaXRvcnkvMTMzMzk2MDE4",
"ghId": 600132099,
"name": "psg2-2223-g6-63",
"issues": {
"pageInfo": {
"hasNextPage": true,
"endCursor": "WzI2MjAyMDU4NV0"
},
"totalCount": 76,
"nodes": [
{
"id": "Z2lkOi8vcmFwdG9yL0lzc3VlLzI2MDg0ODA4NA",
"title": "Task #2.9 Deployment",
"timelineItems": {
"pageInfo": {
"hasNextPage": false,
"endCursor": "MQ"
},
"totalCount": 1,
"nodes": [
{
"id": "Z2lkOi8vcmFwdG9yL1RpbWVsaW5lSXRlbTo6SXNzdWVFc3RpbWF0ZUNoYW5nZWQvMTExNTc0MDA3",
"data": {
"github_user": {
"id": 313464417,
"gh_id": 100673872,
"login": "JaviFdez7",
"avatar_url": "https://avatars.githubusercontent.com/u/100673872?v=4"
},
"current_value": "2.0"
},
"key": "issue.set_estimate",
"updatedAt": "2023-03-20T01:17:30Z"
}
]
}
},
{
"id": "Z2lkOi8vcmFwdG9yL0lzc3VlLzI2MDg0ODA4Ng",
"title": "Task #2.6 Technical report and task diagram",
"timelineItems": {
"pageInfo": {
"hasNextPage": false,
"endCursor": "MQ"
},
"totalCount": 1,
"nodes": [
{
"id": "Z2lkOi8vcmFwdG9yL1RpbWVsaW5lSXRlbTo6SXNzdWVFc3RpbWF0ZUNoYW5nZWQvMTExMzk1NDM0",
"data": {
"github_user": {
"id": 313464417,
"gh_id": 100673872,
"login": "JaviFdez7",
"avatar_url": "https://avatars.githubusercontent.com/u/100673872?v=4"
},
"current_value": "8.0"
},
"key": "issue.set_estimate",
"updatedAt": "2023-03-15T15:41:06Z"
}
]
}
},
...
The GQLPaginator function is a recursive function that follows the following flow:
Assumptions:
- Arrays only exist in nodes, an array is not contemplated elsewhere.
- When an object has nodes as a property, it is considered a pageable type.
- Pageable types are not contemplated in a simple type.