Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GitHub GraphQL API 分页查询 #323

Open
toFrankie opened this issue Dec 3, 2023 · 0 comments
Open

GitHub GraphQL API 分页查询 #323

toFrankie opened this issue Dec 3, 2023 · 0 comments
Labels
2023 2023 年撰写 生活随笔 一些杂七杂八的文章

Comments

@toFrankie
Copy link
Owner

toFrankie commented Dec 3, 2023

配图源自 Freepik

背景

前不久做 Github Blogger 插件开发时,遇到分页查询的场景,是用于查询 Issue 的。

使用 Github REST API 的话,可以很方便地分页查询,比如:

const {Octokit} = require('@octokit/core')

const octokit = new Octokit({
  auth: 'TOKEN',
})

await octokit.request('GET /repos/{owner}/{repo}/issues', {
  owner: 'OWNER',
  repo: 'REPO',
  per_page: 20,
  page: 1,
})

Related Link: List repository issues

由于它并没有提供 in:title 等更加复杂的搜索方式,只能用 GitHub GraphQL API 实现该需求。

简介

我的需求是根据 titlelabel 来筛选 Issues,并支持分页查询。使用到的 API 是下面这个(Queries search):

借助 afterfirstquery 就能实现,比如:

query Issues {
  search(
    type: ISSUE
    query: "user:toFrankie repo:blog state:open label:2023"
    first: 5
    after: null
  ) {
    issueCount
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      node {
        ... on Issue {
          title
        }
      }
    }
  }
}

如果对 Github Graph API 不熟的话,可以借助 Github 提供的 Explorer 进行验证,不懂可看 Using the Explorer

其实从这里就看得出大概了,结果中的 pageInfo 结构如下

  • startCursor 当前分页的起始锚点
  • endCursor 当前分页结果的结尾锚点
  • hasPreviousPage 向前翻页,是否有更多项目
  • hasNextPage 向后翻页,是否有更多项目

也就是说,如果已知 startCursorendCursor 就能代入 Search 的 afterbefore 参数实现翻页的需求。

如果是按顺序从第一页、第二页......进行翻页的话,从本页的 pageInfo 中取出 endCursor 代入下一个查询的 after 中就行。如果我要从第 1 页调到第 5 页呢?

我试图去寻找 Cursor 的规律,从 Introduction to GraphQL 可知,Github 采用 GraphQL 的 cursor-based pagination 方式以实现翻页。

原来 Cursor 是用 Base64 编码后的字符串。

Y3Vyc29yOjU=
cursor:5

解码后可知是 cursor:offset 的形式,所以,实现跳页只要将其编码为 Base64 再传入 after 即可。如果是首页,可以不传入 after 参数或设为 null

示例

其中 TOKENUSERREPOLABEL 以及 query 等按需调整。

const {Octokit} = require('@octokit/core')
const {encode} = require('js-base64')

const octokit = new Octokit({
  auth: 'TOKEN',
})

const page = 2
const perPage = 5
const offset = (page - 1) * perPage
const pageCursor = offset > 0 ? encode(`cursor:${offset}`) : null

await octokit.graphql(`
  {
    search(
      type: ISSUE
      query: "user:USER repo:REPO state:open label:LABEL"
      first: ${perPage}
      after: ${pageCursor ? `"${pageCursor}"` : null}
    ) {
      issueCount
      pageInfo {
        startCursor
        endCursor
        hasNextPage
        hasPreviousPage
      }
      edges {
        node {
          ... on Issue {
            title
          }
        }
      }
    }
  }
`)

RunKit Demo

References

@toFrankie toFrankie added 2023 2023 年撰写 生活随笔 一些杂七杂八的文章 labels Dec 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2023 2023 年撰写 生活随笔 一些杂七杂八的文章
Projects
None yet
Development

No branches or pull requests

1 participant