ぐるなびのREST APIをHasuraでGraphQLにしてみた

Takeshi Amano
11 min readAug 15, 2018

--

最近いろいろいじくっているGraphQLエンジンのHasuraを使うとPostgresのデータベースに格納したデータに対してGraphQLのクエリが発行できるようになります。

なのでRESTからデータを引っ張ってきてPostgres内に保存すればGraphQLでRESTからGraphQLへの変更が行える事に気づき、ぐるなびのAPIのデータを使って行ってみました。

手順は以下の通り:

  1. Hasuraの設定を行う
  2. データ格納するテーブルを設定する
  3. テーブル間のrelationshipを設定する
  4. ぐるなびAPIからデータを取ってきてPosgres内に格納する
  5. GraphQLのクエリを発行してみる

基本これだけ。NodeJS内でGraphQL使ってデータの格納を行いますが、その他の追加のコーディングは必要ありません。

では実際にやってみましょう。

  1. Hasuraの設定を行う

HasuraはHerokuDocker経由でインストール可能ですが、今回はDockerを使ってみます。

dockerとdocker-composeをまず自分のマシン内にインストールしてください。

このページに説明があるように、まずdocker-compose.yamlを空のディレクトリ内にダウンロードします。

$wget https://raw.githubusercontent.com/hasura/graphql-engine-install-manifests/master/docker-compose/docker-compose.yaml

その後dockerを起動します。

$ docker-compose up -d

これで問題なければ以下のURLからHasuraが立ち上がります。

http://localhost:8080/console
HasuraのGraphiQLの画面が立ち上がります。

これでHasuraが使えるようになりました。

2. データ格納するテーブルを設定する

ぐるなびのレストランの基本情報を格納するrestaurantテーブルとレストラン情報の多言語の詳細を格納するrestaurant_descriptionテーブルを用意します。

Hasuraではテーブルの追加にはwebのコンソールから行います。まずページトップの”DATA"をクリックしてAdd Tableをクリックして、テーブル追加ページにいきます。

今回はレストランを格納するrestaurantテーブルを以下の内容になるように追加していきます。

idはprimary keyとして自動で増える様にInteger (auto-increment)を指定しましょう。

Nullableをチェックして必須項目でないところを指定します。またgurunavi_idのUniqueをチェックしておいて、foreign keyを後で指定できるように

“Create”をクリックして、テーブル作成は完了です。

次にrestaurantとjoinするrestaurant_descriptionテーブルを用意します。ぐるなびには多言語でレストランの詳細を返すAPIがあるのでその情報をこのテーブルに格納します。

langというカラム内に言語コードを保存します。ぐるなびAPIでは以下の言語コードが扱えます。その他にもbusiness_hourなど違う言語でお店の情報を保存します。

ja: 日本語, zh_cn: 中国語 (簡体字), zh_tw: 中国語 (繁体字), ko: 韓国語, en: 英語

Primary Keyはidを選択して、”Create”をクリックして保存は完了です。

3. テーブル間のrelationshipを設定する

次にこのテーブル間のrelationshipを定義します。relationshipを定義する事でテーブル間を結合する以下のようなGraphQLのクエリが発行できるようになります。

query restaurant {
restaurant {
id
name
restaurant_descriptions {
id
lang
pr_short
}
}
}

Hasuraでは1:nの関係をArray relationshipと呼び、1:1の関係をObject relationshipと呼んでいます。

restaurantとrestaurant_descriptionは1:nの関係なのでArray relationshipを設定します。

まず最初にrestaurant_descriptionテーブルからrestaurantテーブルへ対してのforeign keyを設定します。

restaurant_descriptionのModifyタブからgurunavi_idのforeign keyの設定を行います。

これをSaveして設定を完了してください。

そしてrestaurantテーブルからRelationshipsタブに行くと以下の様な画面が出てきてArray relationshipを設定しない?と出てくるのでAddをクリックして、先に進めましょう。

このrelationshipの名前はrestaurant_descriptionsとでもしておきましょうか。保存後以下の画面になります。

“+ Add a manual relationship”はforeign keyの設定がない状態でテーブル間のrelationshipを作るのに使います。

これでrelationshipの設定は完了です。

4. ぐるなびAPIからデータを取ってきてPosgres内に格納する

今回はNodeJSのスクリプトを使ってデータをローカルのpostgresに保存します。

こちらが今回のコードのgithubです。

まずこのコードをcloneします。

$git clone git@github.com:moksahero/hasura-gurunavi-graphql.git

レストラン検索APIでレストランの基本情報を取得し、restaurantテーブルに保存します。import_restaurants.jsにコードがあります。

その後多言語版レストラン検索APIで日本語や外国語のレストランの説明分をrestaurant_descriptionテーブルに保存します。import_restaurant_descriptions.jsにコードがあります。

NodeJSのコードを直接見てもらえればいいので、記事内では詳細な説明は行いませんが、mutationを使ってpostgresに対してデータを追加しています。

各ファイルの中の[replace with keyid]をぐるなびWebサービスから提供されるkeyidで置き換えてください。

置き換えた後はnpmインストールを行い必要なモジュールのgraphqurlとaxoisをインストールします。

$npm install

graphqurlはHasuraチームが作成したGraphQLのクエリをシンプルに呼べるようにしたライブラリです。Apolloの上に実装されています。

そしてnode経由でスクリプトを動かします。自分のマシンのNodeのバージョンはv9.11.1です。

$node import_restaurants.js

このコードでは銀座近辺のレストラン10件をareacode_l: ‘AREAL2101’から10件ほど保存しています。

これでエラーが出ずに終了すればrestaurantテーブルへのインポートは終了です。

エラーがある場合はコード内の以下からconsole.log()をしているのでエラーの詳細が表示されます。

await client.query(createRestaurantDescriptionMutation, restaurantDescriptionDetails).catch(error => {
console.log(JSON.stringify(error, null, 2))
})

同様に以下のコマンドを走らせ、言語毎のレストランの情報をrestaurant_descriptionテーブルにインポートします。

$node import_restaurant_descriptions.js

こちらもエラーが出なかったらインポート完了です。

5. GraphQLのクエリを発行してみる

データが格納できたので、実際クエリを発行してみます。

http://localhost:8080/console

このURLからHasuraのconsoleに入り、以下のクエリを発行してみましょう。

query restaurant {
restaurant {
id
name
name_kana
gurunavi_id
}
}

きちんとrestaurantテーブル内の指定したカラムだけが返ってきていますね。

今度はrestaurantとrestaurant_descriptionをjoinしたクエリを発行してみましょう。

query restaurant {
restaurant {
id
name
restaurant_descriptions {
id
lang
pr_short
}
}
}

Joinされた結果が返ってくるのが確認できますね。

Hasuraはクエリの中にwhere文を追加して結果をフィルタリングできます。langがenかjaのrestaurant_descriptionだけのクエリを発行してみましょう。

query restaurant {
restaurant {
id
name
restaurant_descriptions (
where: {lang: {_in: ["en", "ja"]}}
)
{
id
lang
pr_short
}
}
}

英語と日本語だけの詳細情報が返ってきましたね。

ここではwhere: {lang: {_in: [“en”, “ja”]}}を指定して結果をフィルタリングしています。Hasuraはその他のフィルターはHasuraの以下のページに詳細があります。

Postgresにデータを突っ込むだけでSQLライクなGraphQLのクエリが発行できるようになるHasura、いろんな可能性を感じています。

--

--

Takeshi Amano

広島出身、アムステルダム在住。レガシーシステムをPWA化したり、Jamstackで遊んだりしてます。最近はProduct Managementの勉強してます。