やなぎにっき

学んだことの記録

Node.jsでGitHub GraphQL APIを実行する

GitHubの草をコマンドライン上で表示するnpmを作りました。

www.npmjs.com

このnpmではGitHubの草情報を表示するために、日別のContribution数を取得しています。 今回初めてGraphQLを使ったので使い方をメモしておきます。

最初はAPIを使わず https://github.com/users/<username>/contributionssvgをfetchして配列形式で取得していたのですが、このページが正式のものか分からなかったこともあり、GraphQL APIでContributionが取得することにしました。

Contributionの取得はREST APIの方では見当たらなかったので現時点ではおそらくGraphQL APIでしかできないようです。

今回Node.jsでGitHub GraphQL APIを使うにあたって、GitHubが提供しているnpm @octokit/graphqlを使用しました。

github.com

サンプルコード

公式READMEに記載されているサンプルコードです。

GraphQLを実行するためのトークンと、欲しいデータを指定するクエリを設定する必要があります。

const graphqlWithAuth = graphql.defaults({
  headers: {
    authorization: `token secret123`,
  },
});
const { repository } = await graphqlWithAuth(`
  {
    repository(owner: "octokit", name: "graphql.js") {
      issues(last: 3) {
        edges {
          node {
            title
          }
        }
      }
    }
  }
`);

トークンの設定

トークンの取得

GitHubのGraphQLを実行するためにはGitHubの個人アクセストークンが必要です。

自分のケースの場合、権限のスコープは何も設定していなくても問題なく実行できましたが、用途に応じて設定します。

個人アクセストークンを使用する - GitHub Docs

トークンの設定

トークンはGitHub上に公開してしまわないよう直書きにせず.envファイルに環境変数としてトークンを設定し、dotenvライブラリを使って取得します。

motdotla/dotenv

.env

GITHUB_TOKEN = <your_token>

jsファイル

const dotenv = require('dotenv')

// .envファイルから環境変数を読み込む
dotenv.config();

const graphqlWithAuth = graphql.defaults({
    headers: {
      authorization: `token `token ${process.env.GITHUB_TOKEN}``
    }
  })

npmとして公開する場合

npmとして公開する場合はユーザー自身のトークンを使います。

今回のnpmではグローバルインストールしてどのディレクトリでも実行したかったため、~/.fooenvのように固有名の環境ファイルをホームディレクトリに作成しました。

環境設定ファイルを読み込むdotenv.config()はデフォルトの場合コマンドを実行しているディレクトリ配下の.envを参照するので、読み込む先を変更したい場合は引数に指定します。

const ENV_PATH = process.env.HOME + '/.grass_env'

await fs.writeFile(ENV_PATH, `GITHUB_TOKEN = ${token}`)
await dotenv.config({ path: ENV_PATH })

クエリの作成

GitHubにはExplorer - GitHub Docsというページがあり、 左側のExplorerから欲しい項目をチェックするだけで自動でクエリを作成してくれます。

今回は日毎のContributionが欲しいので、

user > contributionsCollection > contributionCalendar > weeks > contributionDays の

contributionCountとdateをチェックしました。

f:id:yana_g:20210601155654p:plain

query getContribution {
  user(login: "yana-gi") {
    contributionsCollection {
      contributionCalendar {
        weeks {
          contributionDays {
            contributionCount
            date
          }
        }
      }
    }
  }
}

▶︎ボタンを押すと以下のような結果が返ってきます。

{
  "data": {
    "user": {
      "contributionsCollection": {
        "contributionCalendar": {
          "weeks": [
            {
              "contributionDays": [
                {
                  "contributionCount": 0,
                  "date": "2020-05-31T00:00:00.000+00:00"
                },
                {
                  "contributionCount": 0,
                  "date": "2020-06-01T00:00:00.000+00:00"
                },
                {
                  "contributionCount": 0,
                  "date": "2020-06-02T00:00:00.000+00:00"
                },
                {
                  "contributionCount": 0,
                  "date": "2020-06-03T00:00:00.000+00:00"
                },
                {
                  "contributionCount": 0,
                  "date": "2020-06-04T00:00:00.000+00:00"
                },
                {
                  "contributionCount": 0,
                  "date": "2020-06-05T00:00:00.000+00:00"
                },
                {
                  "contributionCount": 0,
                  "date": "2020-06-06T00:00:00.000+00:00"
                }
              ]
            },
            {
              "contributionDays": [
                {
                  "contributionCount": 0,
                  "date": "2020-06-07T00:00:00.000+00:00"
                },
-省略-

クエリには変数を指定することもできます。

query getContribution($userName:String!) {
  user(login: $userName) {
    contributionsCollection {
      contributionCalendar {
        weeks {
          contributionDays {
            contributionCount
            date
          }
        }
      }
    }
  }
}
// QUERY VARIABLES
{
  "userName": "yana-gi"
}

実際のコード

トークンとクエリを設定すれば、データを取得することができます。

実際に今回作ったnpmの該当コードを切り取ってみました。(一部改変)

const { graphql } = require('@octokit/graphql')
const dotenv = require('dotenv')

dotenv.config()

const fetchContribution = async ({ userName }) => {
  const graphqlWithAuth = graphql.defaults({
    headers: {
      authorization: `token `token ${process.env.GITHUB_TOKEN}``
    }
  })

  const query =
    `query getContribution($userName:String!) {
      user(login: $userName) {
        contributionsCollection {
          contributionCalendar {
            weeks {
              contributionDays {
                contributionCount
                date
              }
            }
          }
        }
      }
    }`
  return await graphqlWithAuth(query, { userName: userName })
}
async function main (username) {
  const response = await fetchContribution({ userName: username })
  const contributionWeeks = response.user.contributionsCollection.contributionCalendar.weeks
  console.log(contributionWeeks)
}

main(‘yana-gi’)

参考

GitHubの草の情報をAPIで取得する方法

Node.js で GitHub GraphQL API を使用する (@octokit/graphql)|まくろぐ

GraphiQLを使ってGitHubのGraphQL APIをさわってみた | DevelopersIO