2018年8月16日
2018ワールドカップのGraphQL APIを作りました
(2018-06-20)by Michael Hunger
本記事は、原著者の許諾のもとに翻訳・掲載しております。
ワールドカップ2018の2次予選が始まった後で、私たちは、参加チームについての人々のあらゆる問いに答える 簡単な手段 を作りたいと思いました。
要約
ワールドカップ2018のために、グラフデータベースNeo4jを使ったGraphQL APIを作成しました。試してみたい人は、 ここをクリック してください。
グラフデータベースNeo4jを使ったGraphQL APIの作成
既に私たちは、 ワールドカップについての全てのデータのデータベース を作成して、人々がクエリに使えるようにしましたが、これを、Neo4jのクエリ言語、Cypherを知らない人でもアクセスできるようにしたいと思いました。
GraphQLに助けてもらおう
GraphQLの話をする前に、まず、私たちが作ったNeo4jグラフモデルを見てください。
グラフの中央に WorldCup ノードがあって、その周りにモデルの他のパーツが散らばっています。各トーナメントについて1つのWorldCupノードがあります。
ホスト国である Country(国) が、 HOSTED_BY(開催) という関係でWorldCupに結び付いています。WorldCupノードには、複数の Match(試合) が属していて、それぞれの Countryは 、複数の Player(選手) からなる Squad(チーム) を指名し、これが、ワールドカップトーナメントで選手たちを表します。
選手は、チームが参加する試合のそれぞれについて、スタメン(STARTED)かベンチ入り(SUBSTITUTE)のどちらかとして Appearance(出場) ノードに結び付けられます。 Goal(ゴール) が決まると、AppearanceノードがGoalノードに結ばれます(SCORED GOAL)。
GRANDstackスターターキット
Neo4jの説明はこれで十分なので、GraphQLに戻ります。
GRANDstackは、 GraphQL 、 React 、 Apollo 、 Neo4j Database を、簡単にAPIとアプリを作るための使いやすいバンドルにまとめたものです。GRANDstackはGraphQLのスキーマを使ってGraphQLのクエリを 単一の Neo4jクエリに自動的にトランスパイルし、注釈付きスキーマから、全てのクエリ、ミューテーション、フィールドを自動生成することができます。
GRANDstackのロゴ
GRANDstack.ioスターターキット を使って、既に出来上がっているNeo4jデータベースに重ねてGraphQL APIを作りました。
このGraphQL APIは、バックエンド api
とフロントエンド ui
の2つの部分からなります。バックエンドはGraphQL APIと、さらにGraphQL Playgroundをサービスします。GraphQL Playgroundは、GraphQLクエリのためのとても素敵なブラウザ兼エディタで、データスキーマ、ドキュメント、オートコンプリートを備えています。
私たちはそれを自分たちのレポジトリにforkしてから、 ブランチ worldcup
へマージして、使えるようにしました。
最初のステップは、 GraphQLスキーマ の作成です。私たちの思いついたスキーマは下記のとおりで、これは先ほど見たグラフモデルの中のものに密接に対応しています。
最小限のスキーマは次のとおりです:
GraphQLスキーマの最小限の部分
これを、GRANDstack専用のNeo4jエクステンションをいくつか使ってかなり拡張し、代替マッピングなどを加えました。
― GRANDstackのフルスタックアプリのためのシンプルなスターターキット
スキーマを定義し終わってから、.envファイルを更新して、Neo4jクラウド(https://neo4j.com/cloud/)にホスティングされた私たちのデータベースを指すようにしました。
NEO4J_URI=bolt://c27d992b.databases.neo4j.io
NEO4J_USER=worldcup
NEO4J_PASSWORD=worldcup
これをローカルで動作させるには、 yarn && yarn start
を実行します。すると、Playgroundが http://localhost:4000 でローンチされ、クエリを使って遊ぶことができます。
世界でベストの選手は誰か、というクエリを書くこともできます。
GraphQL Playgroundの画面
もちろん、その選手について、もっと詳しいことを尋ねることもできます。
メッシの詳細についてのクエリの結果
zeit.nowへのデプロイ
これで、デプロイの準備ができました。Node.jsアプリをホスティングしているところなら、どこにでも自分たちのサービスをデプロイできますが、@Will.Lyonに Zeit Now を勧められました。これは、アプリのホスティングに簡単に使える素晴らしいサービスで、小さなプロジェクト向けの使いやすい無料プランがあります。
このサービスをインストールしてから、デプロイ先のディレクトリでnowコマンドを実行するだけです。不変のURLにするには、固定の名前でプロジェクトのエイリアスを作成できます。
このGraphQLサーバは https://worldcup-2018.now.sh/ にデプロイされ、使う準備ができました。このデータセットにかけられるクエリのタイプを見てみましょう。
ポルトガル対モロッコ
この記事を書いている時点で、 ポルトガル が モロッコ と対戦しています。このGraphQLクエリを先ほど定義したプレイグラウンドで実行すると、最新のスコアをチェックできます。
ポルトガル対モロッコの結果
現在ポルトガルが1-0でリードしており、得点者は当然ながらクリスティアーノ・ロナウドでした。
ロナウドってどんな選手?
クリスティアーノについて詳しく知りたいなら、選手についてのクエリも可能です。例えば、下記のクエリでは、彼の生年月日や、これまでのワールドカップでのゴールの回数、さらには、今回のゴールの回数も問い合わせることができます。
彼はワールドカップ2018で4つのゴールを獲得し、通算で7つになりました。つまり、今回のトーナメントで獲得したゴールの数が、前回までのトーナメントでのゴールの合計を超えたことになります。
1990年のドイツのスコア
ドイツは今回のワールドカップでは好調なスタートを切ったとは言えませんが、1990年ワールドカップ決勝のスコアを懐かしむクエリを書いてみましょう。
1966年の敗北
同僚のマークがどうしても見たいそうなので、1996年の結果のクエリも書いてみました。
データを最新に維持する
このデータベースは試合が行われている間、数分ごとにLambdaのジョブで更新されるので、いつクエリを行ってもデータは適切に最新の状態になっているはずです。
ReactのUI
フロントエンド ui
は、基本的には単なるReactアプリで、Apollo Clientを使って私たちのAPIにクエリをかけ、結果をコンポーネントにレンダリングします。
今のReactコードは、ご覧のとおり、とても醜悪で悲惨です。これを課題として残しておきますので、ぜひ、 World Cup GraphQL API を使って、美しいウェブアプリやモバイルアプリを作ってください。
私の(醜悪な)ワールドカップ画面
もちろん、VueやAngularなど、あなたの好きなUIフレームワークを使っても構いません。
アプリは、 .env
ファイルの中のURLに接続します。私たちは、このファイルにローカルの http://localhost:4000
または自分たちのnow.sh URIを書き込みました。
REACT_APP_GRAPHQL_URI=https://worldcup-2018.now.sh/
ここでも、ただ1つの now
コマンドが、私たちのUIもデプロイします。私たちのケースには必要ありませんが、Zeitでは現在、secret credentialsがサポートされています。
GRANDstackハッカソン
幸いなことに、 GRANDstackハッカソン が 優れたアイデアの収集を今も続けていて 、とても素敵な報償も用意されています。
データとモデルの取りまとめに尽力してくれた、同僚の Mark Needham に感謝します。
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa