GraphQL

Learning GraphQL (初めての GraphQL) という本と https://graphql.org/learn/ を読んで勉強したメモです。

便利なツール:

* SWAPI GraphiQL: https://graphql.org/swapi-graphql/
    * GraphiQL とは、GraphQL を Web UI でわかりやすく操作出来る物。Endpoint は決め打ちのようだ。
    * StarWars のデータをもとに作った GraphiQL の例がこちら。
* GraphQL Playground: https://www.graphqlbin.com/v2/new
    * Endpoint を変えられる GraphiQL のような物。cURL コマンドもコピー出来て便利。
    * 例えば SWAPI をこれで読むには以下の Endpoint を設定する。
        * https://swapi-graphql.netlify.app/.netlify/functions/index

上記 SWAPI GraphiQL の左の欄に GraphQL のクエリを入れて実行すると結果が出る。

```graphql
query {
  person(personID:5) {
    name
    birthYear
    created
  }
}
```

```json
{
  "data": {
    "person": {
      "name": "Leia Organa",
      "birthYear": "19BBY",
      "created": "2014-12-10T15:20:09.791000Z"
    }
  }
}
```

これで personID:5 の name, birthYear, created という属性(field)を取得するという意味らしい。クエリの形を Schema と呼ぶ。GraphiQL 画面の右上の Docs を押すと Schema を探せる。上記の Schema を探してみる。

まず以下が見つかる。

query: Root

これはこの GraphQL が Root を検索出来る事を示す。Root というのはトップレベルの型で、この下に検索可能な属性が定義されるので Root を選択すると以下が見つかる。

    person(id: ID, personID: ID): Person

* person: 属性(field) の名前。
* (id: ID, personID: ID): 引数。この属性 person で id と personID という引数が使える事を現す。
* Person: この属性 person が答える型。

さらに Person を選択すると Person の属性の説明が現れる。

```
    name: String ... 説明 ...
    birthYear: String ... 説明 ...
    eyeColor: String ... 説明 ...
```

これをもとに上記のクエリを解釈すると、person 属性を引数 personID:5 と共に検索し、答えには name, birthYear, created の３つを要求するという意味になる。ちなみに `query` は省略出来るので以下のようにしても同じ。

ぱっと見 person は関数で、name は変数みたいに別のものに見えるが、name は引数が無いだけでどちらも同じ属性 (field) というもの。

```graphql
{
  person(personID:5) {
    name
    birthYear
    created
  }
}
```

クエリに Operation name を付ける事も出来る。これは multi-operation documents というのを使う時だけ必須で省略可能。

```graphql
query NumberFive {
  person(personID:5) {
    name
    birthYear
    created
  }
}
```

クエリは JSON っぽくて JSON じゃないのが気持ち悪いが、JSON の属性だけ抜き出しオプションで引数を付けた物と考えれば良い。例えば

```graphql
{
  person(personID:11) {
    name
    filmConnection {
      films {
        title
      }
    }
  }
}
```

は以下を返す。クエリにコンマが無いのと films が List 型である事を表現していないのが非常に気持ち悪い。これではクエリだけを見て返って来るデータの構造を判断出来ないのではないかという疑問を抱き気持ち悪い。まあだいたいクエリと結果は同じ構造をしている。

```json
{
  "data": {
    "person": {
      "name": "Anakin Skywalker",
      "filmConnection": {
        "films": [
          {
            "title": "The Phantom Menace"
          },
          {
            "title": "Attack of the Clones"
          },
          {
            "title": "Revenge of the Sith"
          }
        ]
      }
    }
  }
}
```

パラメータをクエリに渡したいときは Variable を使う。ただクエリの中に変数名を埋め込むだけでは駄目で、query の後にカッコを書いてパラメータ名と型を宣言する。この場合 `query` キーワードは省略できない。Operation name は省略できる。

```graphql
query ($numPeople: Int) {
  allPeople(first:$numPeople) {
  	people {
  	  name
  	}
	}
}
```

GraphiQL で変数を使う時は右下の QUERY VARIABLES の部分に入力する。

    {"numPeople":3}

結果

```json
{
  "data": {
    "allPeople": {
      "people": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "C-3PO"
        },
        {
          "name": "R2-D2"
        }
      ]
    }
  }
}
```

GraphQL でもデータの更新が出来る。データの更新には `query` の代わりに `mutation` というキーワードを使う。実際には query の実装で更新しようと思えば出来が、規約で更新には `mutation` を使いましょうという事になっているらしい。以下架空のクエリ。

```graphql
mutation {
  setPerson(personID:5 gender:"male") {
    name
    gender
  }
}
```