GraphQLのQueryとMutationについて

GraphQLの公式に書かれているQueriesとMutationsを自分の言葉に変換して、
メモがわりに記事にしておきます。

コードは、公式で利用されているものを使用させていただいています。

公式で書かれている文章で何ができるのかを把握しようとしている最中です。
ハンズオンで動画を見ながらコードを書くこととは別に、公式で書かれている内容に目を通すことでできることの理解が進むことを実感じました。


# Fields(フィールズ)
オブジェクト中のhero以下がfieldという。
オブジェクトを取得したい時はfield以下でfriends fieldを作成する。

```graphql
# 実行クエリ
{
  hero {
    name
    friends {
      name
    }
  }
}
```

レスポンス

```json
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}
```

# Arguments
ある特定のデータを取得したい場合はhuman fieldの引数で値を指定することで値に紐づいた特定のデータを取得することができる。

```graphql
# 実行クエリ
{
  human(id: "1000") {
    name
    height
  }
}
```

レスポンス

```json
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 1.72
    }
  }
}
```

### ネストしているfieldでも引数を受け取ることができる。

```graphql
# 実行クエリ
{
  human(id: "1000") {
    name
    # ネストのfiledに引数を渡す(METER or FOOTのEnum型)
    height(unit: FOOT)
  }
}
```

レスポンス

```json
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 5.6430448
    }
  }
}
```

# Aliases

取得するfieldが同じだが、異なる結果の名前を意図的に変更したい場合にエイリアスを用います。

```graphql
# empireHeroエイリアス
  empireHero: hero(episode: EMPIRE) {
    name
  }
# jediHeroエイリアス
  jediHero: hero(episode: JEDI) {
    name
  }
}
```

レスポンス

```json
{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}
```

### hero fieldを持ちいてempireとjediのキャラクター名を取得したい。

### 引数をそれぞれ指定して取得してきたデータが格納される箱の名前を`empireHero` と`jediHero` としてエイリアスを用いている

# Fragments

```graphql
{
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}
```

レスポンス

```json
{
  "data": {
    "leftComparison": {
      "name": "Luke Skywalker",
      "appearsIn": [
        "NEWHOPE"
      ],
      "friends": [
        {
          "name": "Han Solo"
        }
      ]
    },
    "rightComparison": {
      "name": "R2-D2",
      "appearsIn": [
        "NEWHOPE"
      ],
      "friends": [
        {
          "name": "Luke Skywalker"
        }
      ]
    }
  }
}
```

## Fragmentにargsを渡す
``` graphql
query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}
```

### エイリアスとフラグメントを用いることで、冗長で複雑に見えているコードを簡潔なコードに変えてくれる


# Variables

```graphql
# 接頭辞としての$,型の指定, 変数はrequired
query HeroNameAndFriends($episode: Episode!) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}
```
```
# variables in Client Code
{
  "episode": "JEDI"
}
```
```json
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}
```

## Default variables
変数にデフォルトの値を入れられるようにする

```graphql
# 型の横に 「= デフォルト値」と記述
query HeroNameAndFriends($episode: Episode = JEDI) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}
```

# Directives
- クエリの構造を動的に変更させることができる
- 変数を用いたクエリの動的変更も可能
- これがあると柔軟にクエリが扱えて便利
- 現在、Directiveは@includeと@skipの2つ

```graphql
query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    # $withFriendsがfalseのためfriends fieldを含まない
    friends @include(if: $withFriends) {
      name
    }
  }
}
```
variables

```json
{
  "episode": "JEDI",
  "withFriends": false
}
```

```json
// レスポンス
{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}
```

追加または削除のqueryで役に立つ
サーバー側でDirectiveを作成すれば独自の動的変更が可能

# Mutations
mutationしたあとのレスポンスはオブジェクトが返ってくる

```graphql
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}
```

variables

```json
{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}
```

```json
{
  "data": {
    "createReview": {
      "stars": 5,
      "commentary": "This is a great movie!"
    }
  }
}
```

## mutationは複数のフィールドを持つことができる
queryは並行して実行され、mutationは連続して実行されるため

```graphql
mutation ($post: AddPostInput!, $author: AddAuthorInput!) {
  addAuthor(input: [$author]) {
    author {
      name
    }
  }
  addPost(input: [$post]) {
    post {
      postID
      title
      text
    }
  }

```

***

参考

https://graphql.org/learn/queries/