GraphQLを1から勉強しなおしてみた ~ クエリ ~

# はじめに
先日に引き続きGraphQLを一から勉強し直していきます。

前回はこちら。

https://qiita.com/mattsu_mocha/items/89a8a6cd9374b79fec9d

# クエリ
クライアントがサーバーに対してデータを要求するためのリクエストである。

以降でクエリ操作の機能を見ていく。

## 引数

```graphql
type Query {
  droid(id: ID!): Droid
}
```

GraphQLではネストされているフィールドでも引数を指定することができる。

```graphql
type Post {
  id: ID!
  title: String
  content: String
  comments(limit: Int, offset: Int): [Comment]
}

type Comment {
  id: ID!
  text: String
  author: User
}

type User {
  id: ID!
  name: String
}

type Query {
  post(id: ID!): Post
}


{
  post(id: "1") {
    id
    title
    comments(limit: 10, offset: 1) {
      id
      text
      author {
        id
        name
      }
    }
  }
}
```

## エイリアス
同じフィールドを異なる引数で複数回クエリしたい場合や、フィールド名を変更して結果を取得したい場合に使用する。

```graphql
query {
  # heroクエリの結果をempireHeroで受け取る
  empireHero: hero(episode: EMPIRE) {
    name
  }
  # heroクエリの結果をjediHeroで受け取る
  jediHero: hero(episode: JEDI) {
    name
  }
}
```

## 変数
クエリに変数を引数として渡すことも可能。

```graphql
query HeroNameAndFriends($episode: Episode = JEDI) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}
```

## フラグメント
クエリの中で再利用可能なフィールドのセットを定義するための機能。

同じフィールドのセットを複数の場所で繰り返し使用する際に、コードの重複を避けることができる。

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

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

フラグメント内で変数を使うことも可能である。

```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
      }
    }
  }
}
```

### インラインフラグメント
特にインターフェースやユニオン型を返す際に便利。

```graphql
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    name
    ... on Droid {
      primaryFunction
    }
    ... on Human {
      height
    }
  }
}
```

### メタフィールド
特定のオブジェクトや型に関するメタデータを取得するために使われる。

通常のスキーマ定義には含まれず、GraphQLの仕様に組み込まれている。代表的なメタフィールドには、`__typename`、`__schema`、`__type`等がある。

#### __typename
オブジェクトの型名を返す。

```graphql: request
query {
 search(term: "example") {
   __typename
   ... on User {
     id
     name
   }
   ... on Post {
     id
     title
   }
 }
}
```

```json:response
{
  "data": {
    "search": [
      {
        "__typename": "User",
        "id": "1",
        "name": "Alice",
        "email": "alice@example.com"
      },
      {
        "__typename": "Post",
        "id": "101",
        "title": "GraphQL Introduction",
        "content": "This is an introduction to GraphQL."
      },
      {
        "__typename": "User",
        "id": "2",
        "name": "Bob",
        "email": "bob@example.com"
      }
    ]
  }
}
```

#### __schema
スキーマ全体の情報を取得する。スキーマの検査やドキュメント生成に使われる。


```graphql:request
{
  __schema {
    types {
      name
      fields {
        name
        type {
          name
        }
      }
    }
  }
}
```

```json:response
{
  "data": {
    "__schema": {
      "types": [
        {
          "name": "Query",
          "fields": [
            {
              "name": "user",
              "type": {
                "name": "User"
              }
            }
          ]
        },
        {
          "name": "User",
          "fields": [
            {
              "name": "id",
              "type": {
                "name": "ID"
              }
            },
            {
              "name": "name",
              "type": {
                "name": "String"
              }
            }
          ]
        }
      ]
    }
  }
}
```

#### __type
特定の型に関する情報を取得する。型のフィールドやその型の詳細を知るために使われる。

```graphql:request
{
  __type(name: "User") {
    name
    fields {
      name
      type {
        name
      }
    }
  }
}
```

```json:response
{
  "data": {
    "__type": {
      "name": "User",
      "fields": [
        {
          "name": "id",
          "type": {
            "name": "ID"
          }
        },
        {
          "name": "name",
          "type": {
            "name": "String"
          }
        },
        {
          "name": "email",
          "type": {
            "name": "String"
          }
        }
      ]
    }
  }
}
```

# 参考

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