naopoyo.com
  • Docs
  • Tags
  • Bookmarks
  • Tools
  • About
  • Docs
  • Tags
  • Bookmarks
  • Tools
  • About

目次

© naopoyo

目次

最近更新された記事

🛤️

Rails 8.0 から 8.1 へのアップグレード手順

24分前·2026年02月04日
  • Rails
  • Ruby
🏗️

Rails サービスレイヤー設計の実践ガイド

約2時間前·2026年02月04日
  • Rails
  • Ruby
✒️

エンジニア個人ブログまとめ

約19時間前·2026年02月03日
  • デザイン
  • Next.js
  • Markdown
🐙

octokit.rb で GitHub GraphQL API を使う方法

公開日約3時間前2026-02-04
履歴GitHubで見る
MarkdownRaw Content
  • GitHub
  • GraphQL
  • Ruby

はじめに

GitHub API を Ruby で使うとき、多くの人が octokit.rb を選びます。REST API のドキュメントは豊富ですが、GraphQL API の使い方はあまり知られていません。この記事では、octokit.rb で GraphQL API を使う方法を実例とともに解説します。

この記事のポイント

  • client.post '/graphql' で GraphQL クエリを実行できます
  • レスポンスは Sawyer::Resource オブジェクトで返されるため、メソッド形式またはシンボルキーでアクセスします
  • エイリアスを使い、複数のファイル情報を 1 回のリクエストで取得できます
  • 大量データを扱う場合はバッチに分割してリクエストを実行します
  • GraphQL API はポイント制のレート制限を採用しています

なぜ GraphQL API を使うのか

REST API では、複数のファイルの情報を取得するのに N 回のリクエストが必要です。

# REST API: 100ファイルなら100回のリクエスト
paths.each do |path|
  client.commits(repo, branch, path: path, per_page: 1)
end

GraphQL API を使えば、1回のリクエストで複数の情報を取得できます。

# GraphQL API: 100ファイルでも1〜2回のリクエスト
client.post '/graphql', { query: batch_query }.to_json

GitHub API のレート制限は 1 時間あたり 5,000 リクエストです。大量のファイルを扱うアプリケーションでは、GraphQL による一括取得が効果的です。

基本的な使い方

octokit.rb は主に REST API クライアントとして設計されていますが、post メソッドで GraphQL エンドポイントにアクセスできます。最初に、シンプルな例から始めましょう。

require 'octokit'

client = Octokit::Client.new(access_token: ENV['GITHUB_TOKEN'])

query = <<~GRAPHQL
  query {
    viewer {
      login
      name
    }
  }
GRAPHQL

response = client.post '/graphql', { query: query }.to_json
puts response.data.viewer.login

Sawyer::Resource の扱い

octokit.rb のレスポンスは Sawyer::Resource オブジェクトで返されます。Hash のようにアクセスできますが、複数のアクセス方法があります。状況に応じて使い分けましょう。

response = client.post '/graphql', { query: query }.to_json

# メソッド形式でアクセス
response.data.viewer.login

# シンボルキーでアクセス
response[:data][:viewer][:login]

# dig でネストしたデータにアクセス
response.dig(:data, :viewer, :login)

Hash に変換する

Sawyer::Resource を通常の Hash に変換したい場合は、ネストされたオブジェクトも含めて再帰的に変換する必要があります。以下のヘルパー関数を使うと便利です。

def sawyer_to_hash(obj)
  case obj
  when Sawyer::Resource
    obj.to_h.transform_values { |v| sawyer_to_hash(v) }
  when Array
    obj.map { |v| sawyer_to_hash(v) }
  else
    obj
  end
end

hash = sawyer_to_hash(response)

実践例: 複数ファイルの最終コミット日時を取得

GraphQL API の利点を活かした実践的な例として、GitHub リポジトリ内の複数ファイルの最終コミット日時を一度に取得する方法を紹介します。

GraphQL クエリの構築

GraphQL のエイリアス機能を活用すれば、複数のクエリを 1 つにまとめられます。これにより、N 回のリクエストが不要になります。

def build_batch_query(owner, repo, branch, paths)
  file_queries = paths.each_with_index.map do |path, index|
    <<~GRAPHQL
      file#{index}: object(expression: "#{branch}") {
        ... on Commit {
          history(path: "#{path}", first: 1) {
            nodes {
              committedDate
            }
          }
        }
      }
    GRAPHQL
  end.join("\n")

  <<~GRAPHQL
    query {
      repository(owner: "#{owner}", name: "#{repo}") {
        #{file_queries}
      }
    }
  GRAPHQL
end

実行とレスポンスの解析

paths = ['README.md', 'src/index.js', 'package.json']
query = build_batch_query('octokit', 'octokit.rb', 'main', paths)

response = client.post '/graphql', { query: query }.to_json
repository = response.data.repository

paths.each_with_index do |path, index|
  key = "file#{index}"
  committed_date = repository[key]&.history&.nodes&.first&.committedDate
  puts "#{path}: #{committed_date}"
end

実行すると、以下のような出力が得られます。

README.md: 2024-01-15T10:30:00Z
src/index.js: 2024-01-10T14:20:00Z
package.json: 2024-01-12T09:15:00Z

バッチサイズの考慮

GraphQL API にも制限があります。1 回のクエリで取得できるノード数には上限があるため、大量のファイルを扱う場合はバッチに分割して処理する必要があります。

BATCH_SIZE = 50

def fetch_all_commit_times(client, owner, repo, branch, paths)
  results = {}

  paths.each_slice(BATCH_SIZE) do |batch|
    query = build_batch_query(owner, repo, branch, batch)
    response = client.post '/graphql', { query: query }.to_json

    batch.each_with_index do |path, index|
      key = "file#{index}"
      committed_date = response.dig(:data, :repository, key, :history, :nodes, 0, :committedDate)
      results[path] = committed_date
    end
  end

  results
end

変数を使う

GraphQL クエリに外部から値を渡す場合、変数を使うと安全で読みやすいコードになります。以下のようにクエリで変数を定義し、実行時に値を渡します。

query = <<~GRAPHQL
  query($owner: String!, $name: String!) {
    repository(owner: $owner, name: $name) {
      description
      stargazerCount
    }
  }
GRAPHQL

variables = { owner: 'octokit', name: 'octokit.rb' }

response = client.post '/graphql', { query: query, variables: variables }.to_json
puts response.data.repository.stargazerCount

エラーハンドリング

REST API と異なり、GraphQL はステータスコード 200 を返しながらエラーを返すことがあります。エラーの確認は、レスポンスの errors フィールドをチェックして行います。

response = client.post '/graphql', { query: query }.to_json

if response.errors
  response.errors.each do |error|
    puts "Error: #{error.message}"
  end
else
  # 正常処理
end

レート制限の確認

GraphQL API のレート制限は REST API とは異なり、ポイント制です。複雑なクエリほどコストが高くなるため、rateLimit クエリを使ってコストと残りポイントを確認しましょう。

query = <<~GRAPHQL
  query {
    rateLimit {
      cost
      remaining
      resetAt
    }
    viewer {
      login
    }
  }
GRAPHQL

response = client.post '/graphql', { query: query }.to_json
rate_limit = response.data.rateLimit

puts "このクエリのコスト: #{rate_limit.cost}"
puts "残りポイント: #{rate_limit.remaining}"
puts "リセット時刻: #{rate_limit.resetAt}"

まとめ

octokit.rb で GraphQL API を使う方法を紹介しました。REST API で N 回のリクエストが必要だった処理を、GraphQL で 1〜2 回に削減できます。

ポイントをまとめると、GraphQL API は複数のファイル情報を効率的に取得でき、レート制限が厳しい場面で活躍します。エイリアスを使った一括クエリ実行やバッチ分割による大量データ処理も、octokit.rb で簡単に実装できます。レート制限が気になる場面では、ぜひ GraphQL API を検討してみてください。

参考リンク

  • GitHub GraphQL API ドキュメント
  • octokit.rb リポジトリ