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 が使えないため、双方向リスト的にシーケンシャルなアクセスをするしかないのが面倒なところ。
参考:
- GraphQL / Pagination
- GitHub GraphQL API v4 / Object