hack のためのネタ帳, etc,,,

最新版

公式ページ等

2018-11-01:
GitHub REST API v3 だと認証なし(API 使用頻度に制限あり)、GitHub アカウントによる認証の双方で使えたけど、
GitHub GraphQL API v4 では OAuth token 必須。
カジュアルな使い方だとアカウント設定不要なので v3 のが使い易いかもしれない。

一方、REST API だとフィールドがごっそり降って来てたのが、GraphQL API だと要求したフィールドだけが降ってくるので I/O のペイロードはコンパクトになる気がする。
認証には HTTP リクエストヘッダに以下のフィールドを突っ込む。
Authorization: bearer OAUTH_TOKEN
OAUTH_TOKEN は、GitHub にログインしてアカウントの settings にある Developer settingsPersonal access tokens で生成(generate)したものを使用する。
各 OAUTH_TOKEN に与える権限は後から変更可能だが、OAUTH_TOKEN の値は生成時の 1 回のみ閲覧可能。
紛失したら、OAUTH_TOKEN を失効(revoke)させる。

参考:
POST mehtod で渡すんだけど、通常のエンコード(var1=val1&var2=val2&... 形式)じゃなくて JSON ? で "query" ってキーに GraphQL クエリ(JSON っぽい書式の DSL ?)をそのまま渡す。
ただし、query の値の中に生の改行コードが混じってると Status: 400 Bad Request になる。エスケープシーケンスで \n みたいに表現されてれば問題はないっぽいけど、どこかにドキュメントされてる?

例えば、
# ※1
wget -qSO- \
https://api.github.com/graphql \
--header="Authorization: Bearer ${OAUTH_TOKEN}" \
--post-data='{"query":"query{user(login: \"'"${LOGIN}"'\") {repositories(first:2){totalCount edges{ cursor node{url}} pageInfo{ hasPreviousPage hasNextPage } }}}"}'
で、login 名が $LOGIN のユーザーのリポジトリ、先頭 2 つを挙げる。
改行は
wget -qSO- \
https://api.github.com/graphql \
--header="Authorization: Bearer ${OAUTH_TOKEN}" \
--post-data='{"query":"query{user(login: \"'"${LOGIN}"'\") {repositories(first:2){totalCount edges{ cursor node{url}} pageInfo{ hasPreviousPage hasNextPage } }}}"'$'\n''}'
とか
wget -qSO- \
https://api.github.com/graphql \
--header="Authorization: Bearer ${OAUTH_TOKEN}" \
--post-data='{"query":"query{user(login: \"'"${LOGIN}"'\") {repositories(first:2){totalCount edges{ cursor node{url}}\npageInfo{ hasPreviousPage hasNextPage } }}}"'
は大丈夫だけど、
wget -qSO- \
https://api.github.com/graphql \
--header="Authorization: Bearer ${OAUTH_TOKEN}" \
--post-data='{"query":"query{user(login: \"'"${USERNAME}"'\") {repositories(first:2){totalCount edges{ cursor node{url}}'$'\n''pageInfo{ hasPreviousPage hasNextPage } }}}"'
だと Status: 400 Bad Request になる。

クエリ可能な要素数は first, last で 100 個制限。
なので、要素数の多い項目にクエリかける場合は Pagination 処理が必須。
各要素の cursor を before, after に与えると、first, last の基準位置を設定できる。

例えば、上記 ※1 の処理で、
{"data":{"user":{"repositories":{"totalCount":16,"edges":[{"cursor":"Y3Vyc29yOnYyOpHOANC34w==","node":{"url":"https://github.com/kou1okada/apt-cyg"}},{"cursor":"Y3Vyc29yOnYyOpHOANTakw==","node":{"url":"https://github.com/kou1okada/ruby"}}],"pageInfo":{"hasPreviousPage":false,"hasNextPage":true}}}}}
が得られた場合、整形すると以下のようになるが、
{
  'data': {
    'user': {
      'repositories': {
        'totalCount': 16,
        'edges': [
          {
            'cursor': 'Y3Vyc29yOnYyOpHOANC34w==',
            'node': {
              'url': 'https://github.com/kou1okada/apt-cyg'
            }
          },
          {
            'cursor': 'Y3Vyc29yOnYyOpHOANTakw==',
            'node': {
              'url': 'https://github.com/kou1okada/ruby'
            }
          }
        ],
        'pageInfo': {
          'hasPreviousPage': false,
          'hasNextPage': true
        }
      }
    }
  }
}
その場合、hasPreviousPage が true なら before が可能で、hasNextPage が true なら after が可能なので、
before には先頭の要素の cursor、after には末尾の要素の cursor を食わせればよいので、以下のようになる。
# before
wget -qSO- \
https://api.github.com/graphql \
--header="Authorization: Bearer ${OAUTH_TOKEN}" \
--post-data='{"query":"query{user(login: \"'"${LOGIN}"'\") {repositories(first:2 before:\"'"${CURSOR}"'\"){totalCount edges{ cursor node{url}} pageInfo{ hasPreviousPage hasNextPage } }}}"}'
# after
wget -qSO- \
https://api.github.com/graphql \
--header="Authorization: Bearer ${OAUTH_TOKEN}" \
--post-data='{"query":"query{user(login: \"'"${LOGIN}"'\") {repositories(first:2 after:\"'"${CURSOR}"'\"){totalCount edges{ cursor node{url}} pageInfo{ hasPreviousPage hasNextPage } }}}"}'
hasPreviousPage が false の場合に before、hasNextPage が false の場合に after を与えても、エラーにはならず、
{"data":{"user":{"repositories":{"totalCount":16,"edges":[],"pageInfo":{"hasPreviousPage":false,"hasNextPage":false}}}}}
整形すると
{
  'data': {
    'user': {
      'repositories': {
        'totalCount': 16,
        'edges': [
        ],
        'pageInfo': {
          'hasPreviousPage': false,
          'hasNextPage': false
        }
      }
    }
  }
}
のように空の結果が返って来る。

REST API だと page と per_page 使ってランダムアクセス的な取得が出来ていたのに、2018-11-01 現在の GraphQL API では、少なくとも repositories を例に取ると argument で offset が使えないため、双方向リスト的にシーケンシャルなアクセスをするしかないのが面倒なところ。

参考:

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

フリーエリア

管理人/副管理人のみ編集できます