- Notifications
You must be signed in to change notification settings - Fork28
Octokit plugin to paginate GraphQL Query responses
License
octokit/plugin-paginate-graphql.js
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Octokit plugin to paginate GraphQL API endpoint responses
| Browsers | Load <scripttype="module">import{Octokit}from"https://esm.sh/@octokit/core";import{paginateGraphQL}from"https://esm.sh/@octokit/plugin-paginate-graphql";</script> |
|---|---|
| Node | Install with import{Octokit}from"@octokit/core";import{paginateGraphQL}from"@octokit/plugin-paginate-graphql"; |
Important
As we useconditional exports, you will need to adapt yourtsconfig.json by setting"moduleResolution": "node16", "module": "node16".
See the TypeScript docs onpackage.json "exports".
See thishelpful guide on transitioning to ESM from@sindresorhus
constMyOctokit=Octokit.plugin(paginateGraphQL);constoctokit=newMyOctokit({auth:"secret123"});const{ repository}=awaitoctokit.graphql.paginate(`query paginate($cursor: String) { repository(owner: "octokit", name: "rest.js") { issues(first: 10, after: $cursor) { nodes { title } pageInfo { hasNextPage endCursor } } } }`,);console.log(`Found${repository.issues.nodes.length} issues!`);
There are two conventions this plugin relies on:
- The name of the cursor variable must be
$cursor - You must include a valid
pageInfoobject in the paginated resource (seePagination Direction for more info on what is considered valid)
ThepaginateGraphQL plugin adds a newoctokit.graphql.paginate() method which accepts a query with a single$cursor variable that is used to paginate.
The query gets passed over to theoctokit.graphql()-function. The response is then scanned for the requiredpageInfo-object. IfhasNextPage istrue, it will automatically use theendCursor to execute the next query untilhasNextPage isfalse.
While iterating, it continually merges allnodes and/oredges of all responses and returns a combined response in the end.
WarningPlease note that this plugin only supports pagination of a single resource - so you cannot execute queries with parallel or nested pagination. You can find more details inthe chapter below.
If your target runtime environments supports async iterators (such as most modern browsers and Node 10+), you can iterate through each response:
constpageIterator=octokit.graphql.paginate.iterator(`query paginate($cursor: String) { repository(owner: "octokit", name: "rest.js") { issues(first: 10, after: $cursor) { nodes { title } pageInfo { hasNextPage endCursor } } } }`,);forawait(constresponseofpageIterator){constissues=response.repository.issues;console.log(`${issues.length} issues found.`);}
Just like withoctokit/graphql.js, you can pass your own variables as a second parameter to thepaginate oriterator function.
awaitoctokit.graphql.paginate(` query paginate($cursor: String, $organization: String!) { repository(owner: $organization, name: "rest.js") { issues(first: 10, after: $cursor) { nodes { title } pageInfo { hasNextPage endCursor } } } } `,{organization:"octokit",},);
You can also use this to pass a initial cursor value:
awaitoctokit.graphql.paginate(` query paginate($cursor: String, $organization: String!) { repository(owner: $organization, name: "rest.js") { issues(first: 10, after: $cursor) { nodes { title } pageInfo { hasNextPage endCursor } } } } `,{organization:"octokit",cursor:"initialValue",},);
You can control the pagination direction by the properties defined in thepageInfo resource.
For a forward pagination, use:
pageInfo {hasNextPageendCursor}
For a backwards pagination, use:
pageInfo {hasPreviousPagestartCursor}
If you provide all 4 properties in apageInfo, the plugin will default to forward pagination.
Nested pagination with GraphQL is complicated, so the followingis not supported:
awaitoctokit.graphql.paginate((cursor)=>{constissuesCursor=cursor.create("issuesCursor");constcommentsCursor=cursor.create("issuesCursor");return`{ repository(owner: "octokit", name: "rest.js") { issues(first: 10, after:${issuesCursor}) { nodes { title, comments(first: 10, after:${commentsCursor}) { nodes: { body } pageInfo { hasNextPage endCursor } } } pageInfo { hasNextPage endCursor } } } }`;});
There is a great video from GitHub Universe 2019Advanced patterns for GitHub's GraphQL API by@ReaLoretta that goes into depth why this is so hard to achieve and patterns and ways around it.
You can type the response of thepaginateGraphQL() anditerator() functions like this:
awaitoctokit.graphql.paginate<RepositoryIssueResponseType>((cursor)=>{return`{ repository(owner: "octokit", name: "rest.js") { issues(first: 10, after:${cursor.create()}) { nodes { title } pageInfo { hasNextPage endCursor } } } }`;});
You can utilize thePageInfoForward andPageInfoBackward-Interfaces exported from this library to construct your response-types:
import{PageInfoForward}from"@octokit/plugin-paginate-graphql";typeIssues={title:string;};typeIssueResponseType={repository:{issues:{nodes:Issues[];pageInfo:PageInfoForward;};};};// Response will be of type IssueResponseTypeconstresponse=awaitoctokit.graphql.paginate<IssueResponseType>((cursor)=>{return`{ repository(owner: "octokit", name: "rest.js") { issues(first: 10, after:${cursor.create()}) { nodes { title } pageInfo { hasNextPage endCursor } } } }`;});
ThePageInfoBackward contains the propertieshasPreviousPage andstartCursor and can be used accordingly when doing backwards pagination.
About
Octokit plugin to paginate GraphQL Query responses
Topics
Resources
License
Code of conduct
Contributing
Uh oh!
There was an error while loading.Please reload this page.