GraphQLの構文まとめてみた

## はじめに

[前回の記事](https://qiita.com/h-i-ist/items/160822552fc9842627b9)では、GraphQLについて軽く触れましたが、その時の理解は浅かったため、今回は深めることを目的として、GraphQLの構文をまとめてみました。

## スキーマ

GraphQLのスキーマは、サーバーがクライアントに提供するデータ構造とAPIの操作を定義します。ここでは、スキーマ定義の基本的な構成要素を見ていきます。

### Type

**Type**はGraphQLの核となる部分です。データの形状を定義し、クエリやミューテーションで扱うオブジェクトの「設計図」となります。

```graphql
type Book {
  id: ID!
  title: String!
  author: String
}
```

上記の`Book`タイプでは、`id`と`title`フィールドが非Nullであることが`!`によって指定されています。これは、これらのフィールドがクエリの結果に必ず含まれるべきであることを意味します。一方で、`author`フィールドには`!`が付いていないため、このフィールドはnullを許容します。つまり、`author`フィールドが値を持たない場合があることを示しています。

また、リストを扱う場合には、フィールドの型を`[]`で囲みます。例えば、複数の著者を持つ書籍を表現したい場合、以下のように定義することができます。

```graphql
type Book {
  id: ID!
  title: String!
  authors: [String]  # 著者のリスト
}
```

この定義では、`authors`フィールドは文字列のリストを値として持つことができ、各著者の名前を含めることができます。リスト自体がnullを許容するかどうか、リストの各アイテムがnullを許容するかどうかは、`!`の使用によって制御されます。

### **Field**

**Field**は、Type内に定義される個々のデータ項目です。上の`Book`タイプ例では、`id`、`title`、`author`がFieldにあたります。

### **Interface**

**Interface**は、異なるTypeが共有するFieldを定義するために使用されます。Interfaceを実装するTypeは、そのInterfaceのすべてのFieldを含む必要があります。

```graphql
interface Character {
  id: ID!
  name: String!
}

type Human implements Character {
  id: ID!
  name: String!
  totalCredits: Int
}
```

### Union

**Union**は、複数のTypeを一つのTypeとして扱うことができます。これにより、異なるTypeのオブジェクトを同じクエリで返すことができます。

```graphql
union SearchResult = Book | Author

type Query {
  search(query: String!): [SearchResult]
}
```

### **Scalar**

**Scalar**型は、GraphQL内での基本的なデータの単位です。これらは具体的な単一の値を表し、複雑なオブジェクト型の構築ブロックとして機能します。GraphQLは以下の5つの組み込みScalar型を提供しています。

- **`String`**：UTF-8文字列。
- **`Int`**：符号付き32ビット整数。
- **`Float`**：符号付き倍精度浮動小数点数。
- **`Boolean`**：`true`または`false`の論理値。
- **`ID`**：一意の識別子。`String`と同じようにシリアライズされますが、IDとして特別扱いされ、オブジェクトを一意に識別するために使用されます。

これらのスカラー型は、単純なデータ構造の表現に使用されます。例えば、ユーザー名を表すフィールドは`String`型、年齢を表すフィールドは`Int`型になります。

カスタムScalar型を定義して使用することも可能です。これにより、日付や時間、バイト配列など、特定のフォーマットや制約を持つデータをより適切に扱うことができます。

例として、`Date`型のScalarを定義することで、ISO 8601形式の日付文字列を受け入れ、返すことができます。

```graphql
scalar Date

type Event {
  id: ID!
  title: String!
  date: Date
}
```

この`Date`型は、クライアントとサーバー間で日付データを正確にやり取りするためのカスタムScalar型の一例です。

### **Enum**

**Enum**は、特定のフィールドが取りうる値を限定的なセットから選択するために使います。

```graphql
enum BookGenre {
  FICTION
  NONFICTION
  COMIC
}
```

### **Directive**

**Directive**は、GraphQLのクエリ実行の挙動を動的に変更するために使用されます。こ

GraphQL仕様には、組み込みのDirectiveがいくつかあり、さらにカスタムDirectiveを定義して、APIの挙動を拡張することができます。

**組み込みDirective**

- **`@include(if: Boolean)`**：このDirectiveは、指定された条件が`true`の場合にのみフィールドを含めます。
- **`@skip(if: Boolean)`**：このDirectiveは、指定された条件が`true`の場合にフィールドをスキップします。
- **`@deprecated(reason: String)`**：このDirectiveは、フィールドや列挙値が非推奨であることを示します。`reason`引数に非推奨の理由を指定できます。

カスタムDirectiveを定義して、認証やアクセス制御など、独自のロジックをクエリに適用することも可能です。

```javascript
directive @auth(requires: Role = ADMIN) on FIELD_DEFINITION

type User {
  id: ID!
  username: String!
  email: String! @auth(requires: USER)
}
```

この例では、`@auth` Directiveを使用して`email`フィールドに認証ロジックを適用しています。これにより、指定されたロールを持つユーザーのみが`email`フィールドにアクセスできます。

### **Description**

**Description**は、スキーマの各部分に対する説明を提供します。これは、ドキュメント生成に役立ちます。

```graphql
"""
This is a book object representing a single book.
"""
type Book {
  id: ID!
  title: String!
  author: String
}

```

### **Input Type**

**Input Type**は、特にミューテーションで使われる、入力データの形状を定義するために使います。

```graphql
input CreateBookInput {
  title: String!
  author: String
}
```

このように、GraphQLのスキーマには、データ構造と操作を柔軟に定義するための多くの要素が含まれています。次に、実際にデータを取得するためのクエリについて詳しく見ていきます。

## **クエリ**

GraphQLでは、データの取得（**`query`**）、更新（**`mutation`**）、サーバーサイドイベントの購読（**`subscription`**）の三つの主要な操作があります。

### Query

**`Query`** Typeは、読み取り操作（データの取得）を定義するために使用されます。以下の例では、すべての本のリストを取得し、各本の`id`と`title`を要求しています。

```graphql
type Query {
  books: [Book]
}

query {
  books {
    id
    title
  }
}
```

### **Mutation**

**`Mutation`** Typeは、データの作成、更新、削除など、書き込み操作を定義するために使用されます。以下の例では、新しい本を追加するミューテーションを定義しています。

```graphql
type Mutation {
  createBook(input: CreateBookInput): Book
}

mutation {
  createBook(input: {title: "GraphQL入門", author: "xxxxx"}) {
    id
    title
  }
}
```

### **Subscription**

**Subscription**は、GraphQLで定義された一種の操作であり、クライアントがサーバーからリアルタイムのデータ更新を購読するために使用されます。これは、WebSocketsなどの持続的な接続を通じて実装されることが多く、特にチャットアプリケーションやリアルタイムの通知システムで使用されます。

以下は、書籍の追加をリアルタイムで購読する簡単な例です。

```graphql
type Subscription {
  bookAdded: Book
}

subscription {
  bookAdded {
    id
    title
    author
  }
}
```

この例では、新しい書籍が追加されるたびに、**`bookAdded`**サブスクリプションを通じてその書籍の情報が購読者にプッシュされる構成になっています。これにより、アプリケーションはリアルタイムに新しい書籍の追加をユーザーに通知することができます。

### **Variables**

クエリやミューテーション内で変数を使用することで、クエリの再利用性を高めることができます。変数は`$`記号で始まります。

```graphql
mutation CreateBook($input: CreateBookInput!) {
  createBook(input: $input) {
    id
    title
  }
}
```

### **Fragment**

**`Fragment`** は、複数のクエリやミューテーションで再利用可能なフィールドの集合を定義するために使用します。これにより、クエリの複雑さを減らすことができます。

```graphql
fragment BookDetails on Book {
  id
  title
  author
}

query {
  books {
    ...BookDetails
  }
}
```

## まとめ

この記事を通じて、GraphQLの基本概念、スキーマ定義、タイプシステム、さらには操作タイプ（クエリ、ミューテーション、サブスクリプション）、変数の使用、フラグメントの利用など、GraphQLの中核となる構文について概観しました。これらの内容をまとめることで、GraphQLに関する理解が一層深まりました。