【初心者向け】GraphQLで国を知るドリル

おはこんばんちは、海外旅行に行きたいちーずです。

GraphQLを「超なんとなく」で使っていたため、基本文法まとめようと思ったら
いつの間にかクイズになってました。
GraphQLをはじめてみたい！という人はぜひチャレンジしてみてください！！

## ルール
今回のクイズでは、publicで公開されている「国API」を使って、

* schemaの読み方
* GraphQLの基本的なクエリの書き方

を学んでいきます。

このAPIでは、`大陸 - continent` / `国 - country` /  `言語 - language` の取得ができます。

▼ 今回使う国APIのgithub 

https://github.com/trevorblades/countries

下記のplaygroundを使って、実際にクエリを実行してみて答えに辿り着けるかチャレンジしてみてください！

▼ playground

https://countries.trevorblades.com/


<details><summary>schema (クリックすると見れるよ)</summary><div>


```schema.graphql
directive @cacheControl(
  maxAge: Int
  scope: CacheControlScope
) on FIELD_DEFINITION | OBJECT | INTERFACE
enum CacheControlScope {
  PUBLIC
  PRIVATE
}

type Continent {
  code: ID!
  name: String!
  countries: [Country!]!
}

input ContinentFilterInput {
  code: StringQueryOperatorInput
}

type Country {
  code: ID!
  name: String!
  native: String!
  phone: String!
  continent: Continent!
  capital: String
  currency: String
  languages: [Language!]!
  emoji: String!
  emojiU: String!
  states: [State!]!
}

input CountryFilterInput {
  code: StringQueryOperatorInput
  currency: StringQueryOperatorInput
  continent: StringQueryOperatorInput
}

type Language {
  code: ID!
  name: String
  native: String
  rtl: Boolean!
}

input LanguageFilterInput {
  code: StringQueryOperatorInput
}

type Query {
  continents(filter: ContinentFilterInput): [Continent!]!
  continent(code: ID!): Continent
  countries(filter: CountryFilterInput): [Country!]!
  country(code: ID!): Country
  languages(filter: LanguageFilterInput): [Language!]!
  language(code: ID!): Language
}

type State {
  code: String
  name: String!
  country: Country!
}

input StringQueryOperatorInput {
  eq: String
  ne: String
  in: [String]
  nin: [String]
  regex: String
  glob: String
}

scalar Upload
```

</div></details>




## 第一問: 世界のすべての大陸名を答えよ

<details><summary>答え</summary><div>

アジア大陸 / ヨーロッパ大陸 / アフリカ大陸 / オーストラリア大陸 / 北アメリカ大陸 / 南アメリカ大陸 / 南極大陸 の七つでした！！

ちなみに大陸の分け方は諸説あるみたいです。
日本の社会の授業では「六大陸」だったような...？

https://fundo.jp/326717

```graphql
query {
  continents {
    name
  }
}
```

</div></details>


<details><summary>解説: schemaの基本的な型  / queryの書き方  </summary><div>

### schemaの見方
#### 1. ルート型を見つける
ルート型には、下記の3種類があります。

* Query - データの取得 (get)
* Mutation - データの追加/更新/削除 (post)
* Subscription - データ更新の監視

ルートクエリ型は、`schema`にて定義しなおすこともできます。

```graphql
schema {
  query: query_root
  mutation: mutation_root
  subscription: subscription_root
}
```

今回は「データの取得」をしたいため、「type Query」を探します。

```graphql
type Query {
  continents(filter: ContinentFilterInput): [Continent!]!
  continent(code: ID!): Continent
  countries(filter: CountryFilterInput): [Country!]!
  country(code: ID!): Country
  languages(filter: LanguageFilterInput): [Language!]!
  language(code: ID!): Language
}
```

これが、叩けるクエリです。

#### 2. フィールドの型

GraphQLのschemaのフィールドには大きく分けて**スカラー型**と**オブジェクト型**があります。

##### スカラー型

```
String  :文字列型
Int     :整数型
Float   :浮動小数点型
Boolean :論理型(true / false)
ID      :ID型(ユニークな文字列）
```

##### オブジェクト型
フィールドの集合体をオブジェクト型と言います。
下記のように、定義したtypeをそのまま使います。

```graphql
type User {
  code: ID!
  name: String
}

Query {
  user: User // これがオブジェクト型
}
```

#### `!` is 何

```
type User {
  code: ID!
  name: String
}
```

このように、型の後ろに`!`があるケースがありますが、
これは「nullを許容しない」ことを意味します。


### クエリの書き方
query{} の中にフィールドを列挙していくだけです。
queryごとにDBへのお問い合わせがいくため、なるべくqueryは分割しないほうが良いです。

```graphql
query {
  フィールド名 
}
```

</div></details>

## 第二問: カナダの首都は？

ヒント: カナダのcodeは`CA`です

<details><summary>答え</summary><div>

「Ottawa(オタワ)」でした！
バンクーバーじゃないんですね！！笑

```graphql
query {
  country(code: "CA") {
    capital
  }
}
```

</div></details>


<details><summary>解説: 引数 / input に関して</summary><div>
### 引数 / input

引数としてフィールドに渡す時は、`type`ではなく`input`で定義します。

```scheme
input UserInput {
  code: ID!
}

query {
  user(code: UserInput): [User!]!
}
```

</div></details>


## 第三問: ポンド(GBP)を使われている国は？

<details><summary>答え</summary><div>

* イギリス(United Kingdom)
* ガーンジー島(Guernsey)
* サウスジョージア・サウスサンドウィッチ諸島(South Georgia and the South Sandwich Islands)
* マン島(Isle of Man)
* ジャージー島(Jersey)

案外あるんや！！と思ったのですが、ほぼほぼイギリス周りの島国です

```graphql
query {
  countries (filter: {currency: {eq: "GBP"}}) {
    name
  }
}
```
</div></details>


第三問の拡張なので、説明は割愛させていただきます。

## 第四問: 日本とアメリカの「名前」「絵文字」「大陸名」は？
ヒント: 日本のcodeは`JP` / アメリカのコードは`US`


<details><summary>答え</summary><div>
:flag_jp: :flag_us: 

```graphql
fragment details on Country {
  name
  emoji
  ctinent {
    name
  }
}

query {
  Japan: country(code: "JP") {
    ...details
  }
  America: country(code: "US") {
    ...details
  }
}
```


</div></details>


<details><summary>解説: フラグメント / エイリアス</summary><div>
### フラグメント
複数回登場するコードをフラグメントでまとめることができます。

書き方は typeではなく`fragment on 継承元`のように書いて、
呼び出す時は `{...fragment}`と書きます。
オブジェクトのスプレッド演算子みたいですね！！


### エイリアス
オブジェクトのキーみたいに書くと、エイリアスを切ることができます。
データの取得時にアクセスしやすいよう工夫するときに使います。


</div></details>


---

参考

https://qiita.com/NagaokaKenichi/items/d341dc092012e05d6606