#はじめに
初めまして、hinokageと申します。
Qiitaへの記事投稿初めて且つ、
プログラミングスクールを卒業したての知識で本記事を書きましたので
お手柔らかにお願いいたします。
#経緯
「Annict」という、有志が開発しているアニメ関連の情報が網羅してあるDBのGraphQLAPIが公開されています。
Railsでアプリ制作をしている際、制作していたアプリ内でこれを利用するためRailsからGraphQLAPIを叩く方法を調べたところ、「Railsで制作したアプリをAPIにする方法としてGraphQLを使用する」という内容の記事は結構な数ヒットするものの、「Railsアプリ内から公開されているGraphQLAPIを叩いてデータ取得する」という内容の記事が全くヒットせず、実装に非常に苦しみました。
私と同じように「有志が制作したGraphQLAPIをRailsで利用したい!」という方に向けて少しでも役に立てるよう本記事を投稿いたします。
#開発環境
- Ruby(2.6.5)
- Ruby on Rails(5.2.3)
#導入
まず最初にGraphQLをrailsで使えるように
Ruby製のGraphQL Client 「graphql-client」を導入します。
(公式リファレンス:https://github.com/github/graphql-client )
gem 'graphql-client'(追記)
gemfileに追記後、bundle install
bundle install
次に、使用したいAPIのアクセストークンの作成を行います。
ここでは例としてGithubのGraphQL APIを使用します。
GitHub APIのアクセストークンは
GitHubの自分のアイコンをクリック
Settings > Developer settings > Personal access tokens >Generate new token
から作成できます。
(ここでは詳しい作成方法は省略させていただきます。)
httpアダプタ、Schema、クライアント設定のためapplication.rbに以下を追記します。
(今回はgql_testというアプリ名で制作しています。)
require 'rails/all'
require "graphql/client" #(追記)
require "graphql/client/http" #(追記)
module GqlTest(ご自身のアプリ名)
...
AUTH_HEADER = "Bearer xxx"
# xxx=作成した際に表示されたアクセストークン
HTTP = GraphQL::Client::HTTP.new("https://api.github.com/graphql") do
#上記には、接続したいAPIのエンドポイントURLを記入
def headers(context)
{ "Authorization": AUTH_HEADER }
end
end
Schema = GraphQL::Client.load_schema(HTTP)
# 上記を使って API サーバーから GraphQL Schema 情報を取得
Client = GraphQL::Client.new(schema: Schema, execute: HTTP)
# 上記を使ってクライアントを作成
end
これで大まかな設定は完了です。
#クエリ作成
次に取得したいデータのクエリを書きます。
ちなみに
クエリとは
データベース管理システムに対する問合せ(処理要求)のこと。
簡単に書くと
「欲しいデータを取得するためのコード」
です。
GraphQLのクエリの書き方は
https://employment.en-japan.com/engineerhub/entry/2018/12/26/103000
上記のサイトが参考になると思います。もし自分でクエリを書きたい場合はご活用ください。
今回はGitHubAPIを使用するのでクエリは以下のようなものを使用しました。
自分のリポジトリの新しいものから5つ分取得するクエリとなっています。
query {
viewer {
repositories(last:5) {
edges {
node {
name
}
}
}
}
}
また、自分でクエリを書きたい場合はAPIに応じたSchemaを知る必要があります。
ちなみに
Schemaとは
GraphQL APIの仕様を表現するものです。スキーマ定義言語(SDL(Schema Definition Language))を使って表現します。
先程のクエリを例にすると「viewer」「repositories」「node」「name」など全てSchemaです。
API作成時、作成者がデータを取り出す方法をSchemaとして文字に定義しており、
それをAPI使用者がSchemaを用いてデータを取得するために書くコードがクエリだと考えてもらえば
わかりやすいかもしれません。
「クエリがどういうものなのか」を分かりやすく伝えるための自分の中で辿り着いた例えが
辞典でいう目次みたいなものがSchemaです。
例えば、辞典でとある動物を調べたい、
しかしその動物の〇〇類〇〇科〇〇目などは分かるが名前はわからないみたいな時に
目次のページを見ると思います。この目次のページがSchemaです。
目次を見て〇〇類のページを開きます。
またその辞典には〇〇類の最初のページに「〇〇科一覧」みたいな目次があるかもしれません。
これもSchemaです。
つまりはSchemaは
目的のデータに辿り着きたい時の検索手段
みたいなものだと考えれば分かりやすいかもしれません。
その検索手段をAPI作成者側が文字に定義しているのが
schemaだと私は解釈して使用しています。
(間違っていたら申し訳ないので、ぜひ一度GraphQL Schemaとググって調べてください)
さて、Schemaの種類や使い方については
各APIの公式リファレンスを読めば書いてあると思いますが
私は「GraphiQL」というアプリケーションを使用して調べることが多いです。
GraphiQLはSchemaの確認や検索ができるほか、
APIへの接続やクエリ、返ってくるデータの確認ができるため非常に便利なツールとなっています。
このアプリはブラウザ上で使用することもできますが
オススメはスタンドアローンで使用できるダウンロード版です。
https://electronjs.org/apps/graphiql
少し話が逸れてしまいました本題に戻ります。
#実装
先ほどのクエリをcontorollerに追加します。
その際、下記のように記述します。
class BlogsController < ApplicationController
Query = GqlTest::Client.parse <<-GRAPHQL
query {
viewer {
repositories(last:5) {
edges {
node {
name
}
}
}
}
}
GRAPHQL
def index
@works = result
end
private
def result
response = GqlTest::Client.query(Query)
end
end
privateメソッドの下層に
resultというメソッドを用意して
クエリの結果データをrailsで使用できるように加工しています。
そして、使用したいアクション内でresultを用いることで、
結果データを使用することができます。
@worksというインスタンス変数にAPIからの結果データを格納したので
これをviewで使用してみます。最新5件のリポジトリ名が表示されればOKです。
<h2>私が最近作成したリポジトリは以下の5つです</h2>
<%= @works%>
あれ?オブジェクトしか表示されない…?
実はこの時点では取り出したいデータを指定していなかったので
オブジェクトが表示されるだけになっています。
これは以下のようにすると表示することができます。
def index
@works = result.data.viewer.repositories.edges
end
private
def result
response = GqlTest::Client.query(Query)
end
これだけだと、変数内に配列のようにリポジトリ名が複数入っている状態なので、
下記のように表示されてしまいます。
そのため、viewファイルの方でeachメソッドを使い1つずつ表示するようにします。
<% @works.each do |work|%>
<p><%= work.node.name%></p>
<% end %>
…しかしこれだと、追記したコードの意味が分からないですよね。
#コードの解説
実は取得したデータだけでは目的の
「自分の最新リポジトリ5件のタイトル」というデータ以外のものも含まれるので、
クエリで書いたように何の情報が欲しいのかを記述する必要があります。
つまり、「自分の最新リポジトリ5件のタイトルを取得する」というクエリを書いても、
結果として返ってくるデータは「自分の最新リポジトリ5件のタイトル」だけでは無いということです。
GraphiQLを使って、先程と同じクエリを送った時にどのようなデータが返ってくるのか見ると非常にわかりやすいです。
画面左側のコードが先程と同じ「最新リポジトリ5件のタイトルを取得する」クエリです
画面右側はそのクエリをAPIに送った時に返ってきた結果データです。
結果データを見るとクエリで書いたSchemaに値が入って返ってきてるのが分かると思います。
また、コードの書かれ方がハッシュと同じような形でkeyとvalueが含まれているのが分かると思います。
この結果データがハッシュであった場合、リポジトリのタイトルであるnameの値を取り出そうとすると
resultという変数に結果データが格納されていた時
result[:data][:viewer][:repositories][:edges].each do |work|
work[:node][:name]
end
このようなコードを書くと思います。
結果データはハッシュでは無いため、このような取り出し方はできないのですが
(ちなみに結果データはJSON形式で返ってきているようです。)
公式リファレンスを読むとハッシュでkeyになっていたものをメソッドのように扱うことで
上記で書いたハッシュの展開と似たような方法で取り出すことができるようです。
つまり、コードは
def index
@works = result.data.viewer.repositories.edges
end
private
def result
response = GqlTest::Client.query(Query)
end
<% @works.each do |work|%>
<p><%= work.node.name%></p>
<% end %>
と書くことで目的のデータが表示できるようになります。
(夜中に殴り書きしたので色々誤字脱字あるかもしれません…)