雑食日誌

PythonとJS。ときどきチーム開発

GraphQLを試してみた

こんにちは。ぬまたです。
約半年ぶりの投稿です。空けすぎました。
最近AppSyncを触る機会があったので、基礎となるGraphQLを学びたいと思います。

目次

GraphQLとは

GraphQLはフロントエンドがサーバのデータをいい感じに取得するためのクエリ言語です(怒られそう)。 ざっと調べる限りは以下のような特徴がありました。

  • 読み取りと書き込みが分離している
  • エンドポイントが一つ
  • データ群の処理結果などをパラメータに追加できる
  • Schemaや型を定義する
  • 変数やコメントアウトを使うことができる
  • キャッシュが比較的容易

実際に使ってみないとわからないので、GitHub APIで試してみます。 GitHubAPIのバージョン4からGraphQLを導入しています。

参考: - GitHub API v4

検証環境

GitHubのデベロッパーツールを使用します。

GraphQLはエンドポイントをリソースごとに分けずにパラメータで指定します。 GitHubではリクエストを https://api.github.com/graphql に向け、パラメータにクエリを入れています。

GitHub API を試してみる

ログインしているユーザーのメールアドレス取得

単一のリソースfieldsから指定したキーの値を取得できます。 現在ログインしているユーザのメールアドレスを取得してみます。

GitHubviewer という fieldsにログインユーザー情報が入っています。 クエリ内にパラメータ(email)を指定して取得することができます。

クエリ

{
 viewer {
   email
 }
}

結果

{
 "data": {
   "viewer": {
     "email": "nununu.mono@gmail.com"
   }
 }
}

Dockerの関連トピックを取得

fields は引数を取ることができます。 GitHubのDockerトピックに関連するトピックを取得してみます。

クエリ

query {
 topic(name: "docker") {
   relatedTopics {
     name
   }
 }
}

結果

{
 "data": {
   "topic": {
     "relatedTopics": [
       {
         "name": "docker-container"
       },
       {
         "name": "jhipster"
       },
       {
         "name": "docker-image"
       },
       {
         "name": "database"
       },
       {
         "name": "ruby"
       },
       {
         "name": "composer"
       },
       {
         "name": "nginx"
       },
       {
         "name": "yii"
       }
     ]
   }
 }
}

relatedTopics はオブジェクトのリストになっています。 ネストしたオブジェクトのキー(今回は name )を選択できることが異なる点ですね。

リポジトリ内のPR一覧を取得

nodes を使ってリスト値と欲しいパラメータを取得することができます。 今回はよく使うDjangoRESTFrameworkのPR一覧とそれぞれのコミット数を調べてみます。

クエリ

query { 
 repository(owner: "encode" name: "django-rest-framework") { 
   pullRequests(last: 5 states: OPEN) {
     nodes {
       number
       title
       commits {
         totalCount
       }
     }
   }
 }
}

結果

{
 "data": {
   "repository": {
     "pullRequests": {
       "nodes": [
         {
           "number": 6279,
           "title": "Let SearchFilter subclasses dynamically set search fields",
           "commits": {
             "totalCount": 4
           }
         },
         {
           "number": 6282,
           "title": "Ensure serializer and field validators support both lists and tuples",
           "commits": {
             "totalCount": 2
           }
         },
         {
           "number": 6284,
           "title": "Don't force implement get_queryset",
           "commits": {
             "totalCount": 1
           }
         },
         {
           "number": 6286,
           "title": "permissions must return a boolean to allow &/| operator comparison",
           "commits": {
             "totalCount": 3
           }
         },
         {
           "number": 6288,
           "title": "Fix DjangoObjectPermissionsFilter deprecation note",
           "commits": {
             "totalCount": 2
           }
         }
       ]
     }
   }
 }
}

pullRequests の引数にPRが OPEN であることと、最新の5つを取得するよう指定しています。 DjangoRESTFrameworkのGitHubをみると正しそうです。

nodes はPRのリスト値にあたり、その中でPRのNoやコミット数を指定しています。 commitstotalCount パラメータが入っているので、データを全て取得せずに総数を把握することができますね。 自分でSchemaを定義する場合はクライアントが欲しい値を自由に追加することができます。

特定条件のリポジトリ数の取得

GraphQLのPaginationを使ってクエリ結果の総数を取得できます。 Pythonで書かれているスター数1000以上のリポジトリが何個あるか調べてみます。

クエリ

query {
 search(query: "language: Python stars:>1000", type: REPOSITORY) {
   repositoryCount
}

結果

{
 "data": {
   "search": {
     "repositoryCount": 28
   }
 }
}

searchGitHubで定義されているコネクションです。クエリに加えて読み取り開始位置 after などを定義できるようになっています。

今回は querytype に検索したい条件をして、値に repositoryCount を取ることでリポジトリ数を取得しています。 search の引数を変えて、色々な検索をかけられるのはよいですね。

まとめ

今回は読み取りの Query を中心にGraphQLを試してみました。 GraphQLのメリットはクライアントの負担が減ることなのかなという所感です。

Schemaの定義はクライアントの要求を取り入れつつ、データベース内のモデルの知識が求められそうですね。 その辺りも今後調べたいと思います。