はじめに
GraphQLのAPIを触るとき、最初にぶつかるのが「どうやってクエリを試すか」という問題です。Postmanで毎回JSONボディを組み立てたり、curlに-d '{"query": "..."}'をエスケープしながら書いたり……。スキーマにどんなフィールドがあるかを確認するためだけに、別タブでドキュメントを開き直した経験がある方も多いのではないでしょうか。
GraphiQLは、この面倒をブラウザの中だけで解決してくれるGraphQL専用のIDEです。エンドポイントに接続するだけで、スキーマを自動で読み込み、補完付きのエディタでクエリを書きながらその場で実行できます。
とはいえ、読むより触った方が早いと思います。GraphiQLが実際にどう動くのか、まずは手元で確認してみてください。
GraphiQLとは
GraphiQLは、GraphQL仕様を策定しているGraphQL Foundation配下のgraphqlorganizationがメンテナンスしている、React製のGraphQL用IDEコンポーネントです。GraphQL APIのリファレンス実装として長く使われており、Apollo Server・Hasura・GitHub GraphQL APIなど、多くのGraphQLサーバーが管理画面としてGraphiQLをそのまま同梱しています。
主な特徴
- スキーマの自動探索 - イントロスペクションクエリでエンドポイントのスキーマを取得し、型やフィールドをドキュメントパネルに自動生成する
- 補完付きクエリエディタ - フィールド名・引数・型を入力中に補完し、存在しないフィールドを書けばその場でエラー表示する
- Variables・Headersエディタ標準装備 - クエリ本体とは別に、変数やリクエストヘッダーを専用ペインで管理できる
fetcherによるトランスポートの差し替え - HTTP通信に限らず、任意の関数をクエリの実行手段として渡せる
インストール
npm install graphiql graphql react react-dom
yarn add graphiql graphql react react-dom
graphiqlはReactコンポーネントとして提供されているため、react・react-dom・graphqlがpeer dependencyとして必要です。あわせてスタイルシートgraphiql/graphiql.cssの読み込みも忘れないようにしてください。
GraphiQLのサンプルを動かす
GraphiQLは本来、fetcherにHTTPリクエストを行う関数を渡してGraphQLサーバーに接続しますが、このサンプルでは外部ネットワークに依存させず、graphqlパッケージのbuildSchemaとgraphql()関数だけでブラウザ内に小さなGraphQLサーバーを組み立て、fetcherからそれを直接呼び出しています。fetcherはクエリ結果を返す関数でありさえすればよい、というGraphiQLのAPI設計がよくわかる例になっています。
要点だけを抜き出すと、こんな形です。
import { buildSchema, graphql } from 'graphql'
const schema = buildSchema(`
type Book { id: ID!, title: String!, author: String! }
type Query { books: [Book!]! }
`)
const books = [{ id: '1', title: '銀河ヒッチハイク・ガイド', author: 'ダグラス・アダムス' }]
const fetcher = async ({ query, variables }) =>
graphql({ schema, source: query, rootValue: { books: () => books }, variableValues: variables })
// <GraphiQL fetcher={fetcher} />
実際に動かせるものが下です。エディタにはbooksを取得するクエリが最初から入っているので、右上の実行ボタン(▶)を押してみてください。
クエリのauthorの行を削除して再実行すると、結果のJSONから該当フィールドだけが消えるはずです。逆に存在しないフィールド名(例えばprice)を追加すると、実行前の時点でエディタが赤い波線を出して教えてくれます。画面右側の「Docs」ボタンを押すと、buildSchemaで定義したBook型とQuery型がそのままドキュメントとして表示されるのも確認してみてください。
基本的な使い方
実際のプロジェクトでは、公開されているGraphQLエンドポイントに接続することがほとんどです。その場合は@graphiql/toolkitが提供するcreateGraphiQLFetcherを使うのが定番で、エンドポイントURLを渡すだけでHTTP通信用のfetcherが作れます。
import { createRoot } from 'react-dom/client'
import { GraphiQL } from 'graphiql'
import { createGraphiQLFetcher } from '@graphiql/toolkit'
import 'graphiql/graphiql.css'
const fetcher = createGraphiQLFetcher({
url: 'https://your-graphql-endpoint.example.com/graphql',
})
function App() {
return <GraphiQL fetcher={fetcher} />
}
createRoot(document.getElementById('root')).render(<App />)
fetcherさえ差し替えれば、エディタや補完、ドキュメント表示といったGraphiQLの機能はそのまま使えます。実際に外部エンドポイントへ接続するコードは通信環境やCORS設定に結果が左右されるため、ここでは動作サンプルにはせず、コード例のみの紹介にとどめます。
実践的なユースケース
変数(Variables)を使ったクエリを実行する
クエリに引数を渡したい場面では、クエリ文字列に直接値を埋め込むのではなく、GraphiQLの下部に用意された「Variables」ペインにJSONを入力して渡すのが基本の書き方です。fetcherにはvariablesが別引数として渡ってくるので、クエリと変数を分離したまま実行できます。
const query = `query GetBook($id: ID!) {
book(id: $id) { title author }
}`
// Variablesペインに { "id": "1" } と入力して実行する
以下のサンプルではbook(id: ID!)という引数付きのクエリを用意しています。エディタ下部の「Variables」タブを開き、{ "id": "2" }のように書き換えてから実行ボタンを押すと、取得される書籍が変わることを確認できます。
idを"4"のように存在しない値に変えると、bookがnullで返ってくることも確認できます。クエリ本体を書き換えずに条件だけを差し替えられるのが、Variablesペインを使う利点です。
Mutationでデータを更新する
参照だけでなく更新も試したい場合は、GraphiQLのツールバーにある「+」ボタンでタブを増やし、mutationから始まるクエリを書きます。取得系と更新系を別タブで並行して開いておけるので、Mutation実行後にQueryタブへ切り替えて結果を確かめる、という流れが自然に作れます。
type Mutation { addBook(title: String!, author: String!): Book! }
const mutation = `mutation Add($title: String!, $author: String!) {
addBook(title: $title, author: $author) { id title }
}`
下のサンプルはaddBookというMutationを実行すると配列に書籍が1件追加され、続けてbooksクエリを実行するとその追加分が反映されて返ってくる、という一連の流れを試せるようにしています。
エディタにはAddBookとBooksという2つのオペレーションが並んでいます。実行ボタンの隣にあるドロップダウンからAddBookを選んで実行し、その後Booksを選んで再実行すると、addBookで追加した書籍が一覧に増えていることが確認できます。
初期表示クエリと永続化を制御する
社内向けの管理画面にGraphiQLを組み込むときなど、開くたびに決まったクエリを見せたい場面があります。GraphiQLは初期表示クエリをdefaultQueryプロパティで指定できますが、通常はエディタの内容をブラウザのlocalStorageに保存して次回起動時にも復元するため、defaultQueryを変えても2回目以降は前回入力した内容が優先されてしまいます。オンボーディング用の埋め込みなど「毎回同じ状態から始めさせたい」ケースでは、storageプロパティにnullを渡して永続化そのものを無効にします。
<GraphiQL
fetcher={fetcher}
defaultQuery={defaultQuery}
storage={null} // localStorageへの保存を無効化
/>
以下のサンプルはstorage={null}を指定しているため、エディタの内容を書き換えてページを再読み込みしても、常に同じdefaultQueryから始まります(storageを渡さない通常のGraphiQLでは、編集内容がブラウザに保存されて次回も復元されます)。
クエリを適当に書き換えてから画面右上のプレビュー再読み込み(LiveCodesのRunボタン)を押すと、編集内容が保存されず常に同じdefaultQueryに戻ることがわかります。管理画面への埋め込みでは、このstorage={null}とdefaultQueryの組み合わせが「毎回まっさらな状態で試してもらう」ための定番の書き方になります。
まとめ
GraphiQLは、GraphQL APIのスキーマ探索・クエリ作成・実行結果の確認を1つの画面にまとめてくれるIDEです。fetcherさえ用意すればどんなGraphQLサーバーにも接続でき、defaultQueryやstorageといったプロパティで組み込み先に合わせた挙動のカスタマイズもできます。まずは今回のサンプルのように、手元のブラウザでクエリを書きながら動きを確かめてみてください。
