GraphQLで変数を用いたクエリを作成する方法【Ruby on Rails使用】


はじめに

※本記事は
前回の記事「RailsでGraphQL APIからデータを取得・表示する」の追記内容です。
よろしければ前回の記事から読んでいただけると有り難いです(ダイレクトマーケティング

前回の記事で紹介したGraphQLのクエリの書き方において
「変数をクエリの中で使うにはどうすればいいの?」と疑問に持つ方がいらっしゃるかと思います。

私の場合は
REST APIで取得したデータをGraphQL APIに渡したかったので
どうすればクエリに変数を組み込めるんだろう?という疑問を持ちました。

で、「GraphQL クエリに変数渡す」とかググると
やっぱり分かりやすい記事がヒットしない!

というわけで今回も、初学者の方向けに分かりやすく(自分も初学者ですが…
GraphQLのクエリで変数を使う方法を解説しようと思います。

静的なクエリ

今回は以下のクエリを例に説明します。

query {
    repositoryOwner(login:"githubユーザー名") {
        repositories(last:5){
            nodes {
                name
            }
        }
    }
}

githubのユーザー名を指定すると、
指定したユーザーのリポジトリの新しいものから5つ分取得するクエリとなっています。

しかし、この状態だと動的なクエリではないですよね。
クエリにユーザー名を直接書いてしまうと、そのユーザーのリポジトリしか取得できません。

例えば、githubのユーザー名を入力すると、
そのユーザーのリポジトリの最新5つが表示されるといったアプリを作る場合
このクエリだと対応できません。どうすればこのクエリを動的なクエリにできるでしょうか?

このクエリを動的なクエリにするには
variablesというクエリの書き方を理解する必要があります。

variablesとは

variablesとは日本語に訳すと変数のことです。
(この記事を書くために調べて気づいたとか口が裂けても言えない)

ここでは、このvariablesの「書き方」を説明しようと思います。
先ほどのクエリにvariablesを追加して書き直すと下記の様になります。

query ($user: String!) {
    repositoryOwner(login:$user) {
        repositories(last:5){
            nodes {
                name
            }
        }
    }
}

--variables--
{
  "user": "username"
}

書き直す前と後で比較すると違ってくるのが、1行目と2行目、variables以下の3箇所

まず1行目から説明すると

query ($user: String!) {

queryの後に$user: String!という記述が追加されていますが
これはArguments、つまりGraphQLの引数と引数の型を書いています。
また引数userの前に「$」を書くことで、
クエリ外に書いた変数を引数としてクエリ内で使える様にしています。

続いて2行目

repositoryOwner(login:$user) {

書き直す前、loginの値に直接githubのユーザーネームを記述していたのが
$userに変わっていると思います。これは引数で渡されたデータを
loginの値として与えてあげることで動的なクエリにしています。

最後にvariables以下の記述

{
  "user": "username"
}

GraphiQLだとクエリエディタの下にVariablesを書くスペースがあるので
そこに記述すると先ほど説明した、1行目2行目の記述と合わせて
変数userとしてクエリ内で使用できる様になります。

…GraphiQLでの使い方はこれでいいのですが、
Railsのアプリで使用する場合は少し違います。

RailsでのVariablesの書き方

という訳でRailsでの書き方です。

今回はscaffoldで新しく作ったアプリに追記する形で説明していきます。
完成形は「githubユーザーの名を入力すると、そのユーザーの最新リポジトリ5つを表示する」
というものを作成します。

※導入部分は省略いたしますが以下の流れで作成しています。
①アプリ作成
②scaffoldで必要なmodelを生成(今回はuserのみ生成)
④データベース関連の作成、migrate
③前回の記事を参考にgraphql-clientを導入、設定

導入ができたらcontrollerに以下の様に追記します。

controllers/users_controller.rb
class UsersController < ApplicationController
...省略...
  Query = GqlTest(ご自身のアプリ名)::Client.parse <<-GRAPHQL
  query ($user: String!) {
    repositoryOwner(login: $user) {
        repositories(last:5){
            nodes {
                name
            }
        }
    }
}
    GRAPHQL

  def show
    username = @user.name
    @works = result(user: username).data.repository_owner.repositories.nodes
  end

・・・省略・・・
  private
  def result(variables = {})
    response = GqlTest(※ご自身のアプリ名)::Client.query(Query, variables: variables)
  end
end

追記したコードの説明をすると
クエリは
Query = GqlTest(ご自身のアプリ名)::Client.parse <<-GRAPHQL
のコードのあとに先ほど作成したクエリを書いてあげればOKです。

controllers/users_controller.rb
Query = GqlTest(ご自身のアプリ名)::Client.parse <<-GRAPHQL
  query ($user: String!) {
    repositoryOwner(login: $user) {
        repositories(last:5){
            nodes {
                name
            }
        }
    }
}

showアクションで追記したのは
newアクションで登録されたユーザー名を@user.nameで持ってきてusernameに格納するコードと
そのusernameを引数として結果データを取り出すコードです。
user: usernameは
GraphiQLのクエリエディタ下のVariablesスペースに記述したものです。

controllers/users_controller.rb
def show
    username = @user.name
    @works = result(user: username).data.repository_owner.repositories.nodes
end

private下のresultメソッドでは以下の様に追記しました。
前回の記事と違うのは、queryのあとに
variables: variables
の記述をすることでvariablesを使える様にしています。
この部分の詳しい説明はgraphql-clientの公式リファレンスに書いてあるので
ご確認ください。
(公式リファレンス:https://github.com/github/graphql-client

controllers/users_controller.rb
private
  def result(variables = {})
    response = GqlTest(※ご自身のアプリ名)::Client.query(Query, variables: variables)
  end
end

そして、最後にviewのshow.html.erbに変更加えて完成です。

views/show.html.erb
<% @works.each do |work|%>
   <p><%= work.name %></p>
<% end %>

上記のコードはscaffoldで作成したshow.html.erbのお好きな場所に追加していただければ
表示されると思います。

上記の様に表示できれば完成です!

以上です、お疲れ様でした!

(今回も夜中に殴り書きしたので、色々誤字脱字あるかもしれません…)