GraphQL クエリを学ぶ場合,気軽に使える API があると便利だと思う.よく見るのは GitHub GraphQL API や Star Wars API だけど,個人的に Star Wars の映画を観たことがなく,データの理解が難しいため,良さそうな API を探していた.すると,GitHub で公開されている「GraphQL Pokémon」を発見した.GraphQL で「ポケモン(第一世代)」のポケモンを検索することができる.これは楽しそう!さっそく試してみた.
クエリ環境
GraphQL Pokémon には GraphiQL コンソールがあり,ブラウザから簡単にクエリを実行できる.
個人的には GraphQL Playground の Mac アプリをよく使っている.インストールしておくと良いと思う.
GraphQL スキーマ
GraphQL Pokémon の GraphQL スキーマを以下に載せた.要点をまとめると,ポケモンを表現する Pokemon
型を軸とし,ワザを表現する PokemonAttack
型 と Attack
型 / サイズを表現する PokemonDimension
型 / 進化条件を表現する PokemonEvolutionRequirement
型となる.マスタデータとしてはそこそこ揃っている気がする.そして「ポケモン(第一世代)」を対象とするため,ミュウ (No.151) までデータセットに含まれている.
Pokemon
PokemonAttack
Attack
PokemonDimension
PokemonEvolutionRequirement
type Attack { name: String type: String damage: Int } type Pokemon { id: ID! number: String name: String weight: PokemonDimension height: PokemonDimension classification: String types: [String] resistant: [String] attacks: PokemonAttack weaknesses: [String] fleeRate: Float maxCP: Int evolutions: [Pokemon] evolutionRequirements: PokemonEvolutionRequirement maxHP: Int image: String } type PokemonAttack { fast: [Attack] special: [Attack] } type PokemonDimension { minimum: String maximum: String } type PokemonEvolutionRequirement { amount: Int name: String } type Query { query: Query pokemons(first: Int!): [Pokemon] pokemon(id: String, name: String): Pokemon }
クエリ :「ピカチュウ」を検索する
まず,1番簡単なクエリを実行する.pokemon
クエリに name: "Pikachu"
を指定する.取得するフィールドは number (番号)
と name (英語名)
と types (タイプ)
とした.
query {
pokemon(name: "Pikachu") {
number
name
types
}
}
すると「ピカチュウ」を検索できる.ピカチュウは Electric (でんき) タイプであると確認できる.
{ "data": { "pokemon": { "number": "025", "name": "Pikachu", "types": [ "Electric" ] } } }
クエリ :「ピカチュウ」の進化を検索する
evolutions (進化)
フィールドを指定すると進化するポケモンを Pokemon
型で取得できる.
query {
pokemon(name: "Pikachu") {
number
name
types
evolutions {
number
name
types
}
}
}
すると「ピカチュウ」の進化は「ライチュウ」であると確認できる.REST API と異なり,1回のクエリで階層データまで取得できるのは GraphQL のメリットと言える.
{ "data": { "pokemon": { "number": "025", "name": "Pikachu", "types": [ "Electric" ], "evolutions": [ { "number": "026", "name": "Raichu", "types": [ "Electric" ] } ] } } }
クエリ :「ヒトカゲ」の進化を検索する
3段階進化をする「ヒトカゲ」を検索する.英語版だと名前が異なるため,今回は name: "Charmander"
を指定する.
query {
pokemon(name: "Charmander") {
number
name
types
evolutions {
number
name
types
}
}
}
すると「ヒトカゲ (Charmander)」の進化は「リザード (Charmeleon)」と「リザードン (Charizard)」であると確認できる.
{ "data": { "pokemon": { "number": "004", "name": "Charmander", "types": [ "Fire" ], "evolutions": [ { "number": "005", "name": "Charmeleon", "types": [ "Fire" ] }, { "number": "006", "name": "Charizard", "types": [ "Fire", "Flying" ] } ] } } }
クエリ : フラグメントを使う
進化を検索したときに Pokemon
型のフィールドを2箇所に定義していたため,GraphQL クエリの「フラグメント」を使って共通化する.以下のように Pokemon
型のフラグメント pokemonInfo
を定義し,クエリに含めた.さらに今回は取得するフィールドに weaknesses (弱点)
を追加した.
fragment pokemonInfo on Pokemon {
number
name
types
weaknesses
}
query {
pokemon(name: "Pikachu") {
...pokemonInfo
evolutions {
...pokemonInfo
}
}
}
「ピカチュウ」と「ライチュウ」は Ground (じめん) タイプが弱点であると確認できる.フラグメントを使うと GraphQL クエリをシンプルに書けるし,可読性も高くなるため,タイミングを見極めて積極的に使っていく.
{ "data": { "pokemon": { "number": "025", "name": "Pikachu", "types": [ "Electric" ], "weaknesses": [ "Ground" ], "evolutions": [ { "number": "026", "name": "Raichu", "types": [ "Electric" ], "weaknesses": [ "Ground" ] } ] } } }
クエリ :「ピカチュウ」と「ライチュウ」のワザを検索する
attacks (ワザ)
フィールドを指定すると,ポケモンのワザを PokemonAttack
型と Attack
型で取得できる.PokemonAttack
型 では fast (ワザ)
と special (わざマシン)
の2種類のフィールドが定義されている.今回は Pokemon
型に加えて Attack
型も「フラグメント」を使って共通化する.
fragment attackInfo on Attack {
name
type
damage
}
fragment pokemonInfo on Pokemon {
number
name
types
weaknesses
attacks {
fast {
...attackInfo
}
special {
...attackInfo
}
}
}
query {
pokemon(name: "Pikachu") {
...pokemonInfo
evolutions {
...pokemonInfo
}
}
}
すると「ピカチュウ」と「ライチュウ」のワザを取得できる.ワザの英語名を整理すると以下になると思う(間違っている可能性もある).
- ピカチュウ
fast
- Quick Attack (でんこうせっか)
- Thunder Shock (でんきショック)
special
- Discharge (ほうでん)
- Thunder (かみなり)
- Thunderbolt (10まんボルト)
- ライチュウ
fast
- Spark (スパーク)
- Thunder Shock (でんきショック)
special
- Brick Break (かわらわり)
- Thunder (かみなり)
- Thunder Punch (かみなりパンチ)
{ "data": { "pokemon": { "number": "025", "name": "Pikachu", "types": [ "Electric" ], "weaknesses": [ "Ground" ], "attacks": { "fast": [ { "name": "Quick Attack", "type": "Normal", "damage": 10 }, { "name": "Thunder Shock", "type": "Electric", "damage": 5 } ], "special": [ { "name": "Discharge", "type": "Electric", "damage": 35 }, { "name": "Thunder", "type": "Electric", "damage": 100 }, { "name": "Thunderbolt", "type": "Electric", "damage": 55 } ] }, "evolutions": [ { "number": "026", "name": "Raichu", "types": [ "Electric" ], "weaknesses": [ "Ground" ], "attacks": { "fast": [ { "name": "Spark", "type": "Electric", "damage": 7 }, { "name": "Thunder Shock", "type": "Electric", "damage": 5 } ], "special": [ { "name": "Brick Break", "type": "Fighting", "damage": 30 }, { "name": "Thunder", "type": "Electric", "damage": 100 }, { "name": "Thunder Punch", "type": "Electric", "damage": 40 } ] } } ] } } }
クエリ :「イーブイ」と進化ポケモンの画像を検索する
GraphQL スキーマを見ると Pokemon
型に image
フィールドがある.3種類に進化する可能性のある「イーブイ (Eevee)」を検索して,画像を取得する.
fragment pokemonInfo on Pokemon {
number
name
image
}
query {
pokemon(name: "Eevee") {
...pokemonInfo
evolutions {
...pokemonInfo
}
}
}
すると image
フィールドに画像 URL が含まれていた.
{ "data": { "pokemon": { "number": "133", "name": "Eevee", "image": "https://img.pokemondb.net/artwork/eevee.jpg", "evolutions": [ { "number": "134", "name": "Vaporeon", "image": "https://img.pokemondb.net/artwork/vaporeon.jpg" }, { "number": "135", "name": "Jolteon", "image": "https://img.pokemondb.net/artwork/jolteon.jpg" }, { "number": "136", "name": "Flareon", "image": "https://img.pokemondb.net/artwork/flareon.jpg" } ] } } }
「GraphQL Pokémon」の GitHub を見ると,ポケモン画像を使った React サンプルアプリも公開されていた.GraphQL / React / Relay / Material-UI を組み合わせた実装例としても参考になる.以下にサンプルアプリのキャプチャを載せておく.
クエリ : ポケモン一覧を検索する
GraphQL スキーマを見ると,もう1種類 pokemons
というクエリも用意されている.柔軟に検索できるのかと予想したけど,実際には first
パラメータしかなく,最初から何種類のポケモンを取得する?という用途だった.一覧を作る以外は用途はなさそう.
query { pokemons(first: 3) { name } }
今回は first: 3
を指定したため,「フシギダネ(Bulbasaur)」と「フシギソウ (Ivysaur)」と「フシギバナ (Venusaur)」を取得できる.ポケモンの英語名を覚える練習に使えそう.英語名だと本当にわからなかった.
{ "data": { "pokemons": [ { "name": "Bulbasaur" }, { "name": "Ivysaur" }, { "name": "Venusaur" } ] } }
まとめ
- GraphQL クエリを学ぶ場合,気軽に使える API があると便利
- GitHub GraphQL API や Star Wars API 以外にもたくさんある
- 「GraphQL Pokémon」を使うと GraphQL で「ポケモン(第一世代)」のポケモンを検索することができて楽しく学べる!