こんにちは.マンガチームの id:mangano-ito です.最近は GraphQL API の開発を担当しており,GraphQL に関することを勉強したり実践したりしています.今回は開発ツールについてのお話です.
- GraphiQL とは
- GitHub API での使用例
- GraphiQL を導入してみよう
- ツールバーをカスタマイズしてみよう
- ヘッダーやクエリをカスタマイズしてみよう
- 実際に開発ではどう使っているか
GraphiQL とは
graphql/graphiql: GraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.
GraphQL API の使いやすい GUI クライアントです.GUI クライアントなので GraphQL ではなく Graph i QL となっているのがポイントですね.
余談ですが「グラフィキューエル」と呼んでいたら「グラフィクル」だという声をいただき,「グラフィカル」にかけていると気づきました(ちなみにREADME
では読み方が/ˈɡrafək(ə)l/
と示されています).
ライブデモがあるので,どのようなものかはブラウザ上で確認できます.また Electron で実装されたアプリもあり,デスクトップ上でも使うことができます.
GitHub API での使用例
まず GitHub API の Explorer を見てみてください.これは GitHub の GraphQL API をブラウザ上でテストできるツールです.
GitHub にサインインしていれば,自分のアカウントを使って GraphQL API をテストすることができます.実際のデータで確認できて便利です.
お気づきかと思いますが,ここに埋め込まれているクライアントは GraphiQL です.つまり GraphiQL を自分のウェブページにマウントすることができるということが,この例からわかります.
GraphiQL を導入してみよう
こうなるとこの例と同じように,開発しているサービスに特化した GraphiQL を便利に使えるようにしてみたいですね.どのようにすれば使うことができるでしょうか……
より詳しい情報はREADME
をあたっていきましょう.GraphiQL をモジュールとして使うための方法が書かれています.
graphiql/graphiql - GraphiQL (README.md)
ここにお試しで掲載されているケースでは,ただ CDN で配布されたスクリプトを読み込み,ReactDOM.render
で GraphiQL のコンポーネントを任意の要素にマウントすればそれで完了です!
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Simple GraphiQL Example</title> <link href="https://unpkg.com/graphiql/graphiql.min.css" rel="stylesheet" /> </head> <body style="margin: 0;"> <script crossorigin src="https://unpkg.com/react/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script> <script crossorigin src="https://unpkg.com/graphiql/graphiql.min.js"></script> <div id="graphiql" style="height: 100vh;"></div> <script> const fetcher = GraphiQL.createFetcher({ url: '<GraphQL API エンドポイントの URL>' }); ReactDOM.render( React.createElement(GraphiQL, { fetcher: fetcher }), document.getElementById('graphiql'), ); </script> </body> </html>
▲ Usage: UMD Bundle over CDN より
React のコンポーネントをマウントする形になっているのはユニークですね.これだけで GraphiQL の機能がひと通りそろっていて,クエリもできるし,ドキュメンテーションもしっかりと表示できる状態になっています.
もちろんパッケージをnpm install
して使うこともできます,本格的に組み込んで使える場合はこちらが都合よさそうですね.
import React from 'react'; import ReactDOM from 'react-dom'; import GraphiQL from 'graphiql'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; const fetcher = createGraphiQLFetcher({ url: '<GraphQL API エンドポイントの URL>', }); ReactDOM.render( <GraphiQL fetcher={fetcher} />, document.body, );
▲ Usage: NPM module より
fetcher
は,対象となる GraphQL API のエンドポイントを指定しリクエストするために必要なものです.
const fetcher = GraphiQL.createFetcher({ url: '<GraphQL API エンドポイントの URL>' });
以降のコードではこの基本形を基にして拡張してみます.
ツールバーをカスタマイズしてみよう
React のコンポーネントになっていることで,さらに面白い点としては,自分が作って任意のコンポーネントを GraphiQL 上に追加することができることです.
GraphiQL
コンポーネントの属性により注目してみましょう.
<GraphiQL fetcher={fetcher} toolbar={toolbar} />
toolbar
という属性があります.これはその名の通り,ツールバーの設定を記述するための属性です.ここにadditionalContent
という属性を持ったオブジェクトを与えることで,任意の React コンポーネントを追加することができます.
const toolbar = { additionalContent: ( <div> <GraphiQL.Button label="ボタンA" onClick={() => window.alert('こんにちは!')} /> <GraphiQL.Button label="ボタンB" onClick={() => window.alert('さようなら!')} /> </div> ), }; const Editor = () => ( <GraphiQL fetcher={fetcher} toolbar={toolbar} /> ); ReactDOM.render( <Editor />, document.getElementById('graphiql'), );
例えばこのようなコードを書いてみます.GraphiQL.Button
は GraphiQL のツールバーボタンのコンポーネントです.ツールバーに2つのボタンが追加されていることが確認できます.
コードから予想できるように,ボタンをクリックするとアラートが表示されます.
他に,ボタン以外のコンポーネントもあります.メニューは便利そうですね.
const toolbar = { additionalContent: ( <GraphiQL.Menu label="メニュー"> <GraphiQL.MenuItem label="おはよう" onSelect={() => alert('おはよう')} /> <GraphiQL.MenuItem label="おやすみ" onSelect={() => alert('おやすみ')} /> </GraphiQL.Menu> ), }; const Editor = () => ( <GraphiQL fetcher={fetcher} toolbar={toolbar} /> ); // ReactDOM.render 以下省略……
実はロゴ部分を変えることもできたりします.面白いですね.
const Editor = () => ( <GraphiQL fetcher={fetcher} toolbar={toolbar}> <GraphiQL.Logo>マイ GraphiQL</GraphiQL.Logo> </GraphiQL> );
これで任意の機能をツールバーに登録することができることがわかりました.
ヘッダーやクエリをカスタマイズしてみよう
ところで,冒頭にご紹介した GitHub の例ではログイン状態を反映することができていました.
仮にログイン状態のためのAuthorization
ヘッダーが API に必要だとしましょう.私たちが作る GraphiQL にその情報を追加するにはどうすればよいでしょうか?
GraphiQL
コンポーネントの他の属性を見てみましょう.headers
という属性があります.ここにヘッダーの内容を示す JSON 文字列を与えることで,任意の値を追加することができます.
const headers = { 'Authorization': 'Bearer MY_TOKEN', }; const Editor = () => ( <GraphiQL fetcher={fetcher} headerEditorEnabled="true" headers={JSON.stringify(headers, null, 2)} /> );
開発者ツールでリクエストを確認すると,ヘッダーに指定したAuthorization
の値が設定されていることがわかります.
またheaderEditorEnabled
で,リクエストヘッダーがエディター上に表示され,編集もできるようになります.
さらに,この値に state 変数を使うとリアクティブ変化するので……
const MyTokenButton = ({ setToken }) => ( <GraphiQL.Button label='トークンをセット' onClick={() => setToken('NEW_TOKEN')} /> ); const Editor = () => { const [token, setToken] = React.useState(''); const headers = { 'Authorization': (!!token ?`Bearer ${token}`: undefined), }; const toolbar = { additionalContent: <MyTokenButton setToken={setToken} />, }; return ( <GraphiQL fetcher={fetcher} toolbar={toolbar} headerEditorEnabled="true" headers={JSON.stringify(headers, null, 2)} /> ); };
ボタンを押すとヘッダーにトークンが設定されるようになりました.
クエリも同様にquery
属性を設定でき,onEditQuery
で編集されたイベントを受け取ることもできます.
const FavoriteQueryButton = ({ setQuery }) => ( <GraphiQL.Menu label="お気に入りクエリ"> <GraphiQL.MenuItem label="その1" onSelect={() => setQuery("{ favorite1 }")} /> <GraphiQL.MenuItem label="その2" onSelect={() => setQuery("{ favorite2 }")} /> </GraphiQL.Menu> ); const Editor = () => { const [query, setQuery] = React.useState(''); const toolbar = { additionalContent: <FavoriteQueryButton setQuery={setQuery} />, }; return ( <GraphiQL fetcher={fetcher} toolbar={toolbar} query={query} /> ); };
このようにして任意のヘッダーやクエリを設定することができました.よく使うアクションやサービス特有のテンプレートをツールバーボタンから設定できると便利になりそうですね.
実際に開発ではどう使っているか
最後に,自分が担当しているサービスでの実例を紹介します.
GraphiQL に,開発用に以下の3つの機能を追加してみました.
- 自分のログイン情報を自動的に付加できるようにした
- デバッグ機能のためのプリセットや値をツールバーから使えるようにした
- 書いたクエリを共有できるようにして,開発者同士でシェアできるようにした
この中で3番目の「書いたクエリを共有」というのは,上図のように特定の URL でクエリが記入された GraphiQL を開くことができるものです.確認用のクエリを Pull Request で共有できて便利だったりします.
実装はごく単純で,URL の GET パラメーターにクエリを持たせてやりとりしているだけで,簡単に実現できます.
/** * ?query=... に今のクエリを設定する * @param {string} query 更新されたクエリ */ const onQueryUpdated = (query) => { const url = new URL(document.location); url.searchParams.set('query', query); window.history.replaceState(null, null, url); }; /** * ?query=... のクエリを取得する * @returns {string|null} クエリ */ const getCurrentQuery = () => ( new URL(document.location).searchParams.get('query') ); // あとはこれを使うだけ const Editor = () => { const [query, setQuery] = React.useState(getCurrentQuery()); return ( <GraphiQL fetcher={fetcher} query={query} onEditQuery={onQueryUpdated} /> ); };
まだできていないこととして,あらかじめよく使うクエリを何らかの手段で参照できるようにして,スニペットとしてサッと使えるようにしてみたいと思っています.
GitHub API の Explorer では,次のようにExplorer
ボタンからクエリをお手軽に構築できる機能があり,こういう形でスニペットを挿入するイメージです.
GraphiQL 自体が React を使って柔軟に自作コンポーネントを追加できるので,生の要素や状態を管理することなく拡張できて便利です.思いがけず簡単に導入することができたのは面白い体験でした.
*1:隠したり文言を少し変えたりしています
id:mangano-ito
マンガーノ・伊藤、伊藤聡介。アプリケーションエンジニア。マンガチーム所属。2019年12月入社時より現職。
Twitter: @mangano_ito
GitHub: mangano-ito
blog: マンガ〜ノ伊藤ノ〜ト