はじめに
前回の記事では、GraphQLについて軽く触れましたが、その時の理解は浅かったため、今回は深めることを目的として、GraphQLの構文をまとめてみました。
スキーマ
GraphQLのスキーマは、サーバーがクライアントに提供するデータ構造とAPIの操作を定義します。ここでは、スキーマ定義の基本的な構成要素を見ていきます。
Type
TypeはGraphQLの核となる部分です。データの形状を定義し、クエリやミューテーションで扱うオブジェクトの「設計図」となります。
type Book {
  id: ID!
  title: String!
  author: String
}
上記のBookタイプでは、idとtitleフィールドが非Nullであることが!によって指定されています。これは、これらのフィールドがクエリの結果に必ず含まれるべきであることを意味します。一方で、authorフィールドには!が付いていないため、このフィールドはnullを許容します。つまり、authorフィールドが値を持たない場合があることを示しています。
また、リストを扱う場合には、フィールドの型を[]で囲みます。例えば、複数の著者を持つ書籍を表現したい場合、以下のように定義することができます。
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を含む必要があります。
interface Character {
  id: ID!
  name: String!
}
type Human implements Character {
  id: ID!
  name: String!
  totalCredits: Int
}
Union
Unionは、複数のTypeを一つのTypeとして扱うことができます。これにより、異なるTypeのオブジェクトを同じクエリで返すことができます。
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形式の日付文字列を受け入れ、返すことができます。
scalar Date
type Event {
  id: ID!
  title: String!
  date: Date
}
このDate型は、クライアントとサーバー間で日付データを正確にやり取りするためのカスタムScalar型の一例です。
Enum
Enumは、特定のフィールドが取りうる値を限定的なセットから選択するために使います。
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を定義して、認証やアクセス制御など、独自のロジックをクエリに適用することも可能です。
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は、スキーマの各部分に対する説明を提供します。これは、ドキュメント生成に役立ちます。
"""
This is a book object representing a single book.
"""
type Book {
  id: ID!
  title: String!
  author: String
}
Input Type
Input Typeは、特にミューテーションで使われる、入力データの形状を定義するために使います。
input CreateBookInput {
  title: String!
  author: String
}
このように、GraphQLのスキーマには、データ構造と操作を柔軟に定義するための多くの要素が含まれています。次に、実際にデータを取得するためのクエリについて詳しく見ていきます。
クエリ
GraphQLでは、データの取得(query)、更新(mutation)、サーバーサイドイベントの購読(subscription)の三つの主要な操作があります。
Query
Query Typeは、読み取り操作(データの取得)を定義するために使用されます。以下の例では、すべての本のリストを取得し、各本のidとtitleを要求しています。
type Query {
  books: [Book]
}
query {
  books {
    id
    title
  }
}
Mutation
Mutation Typeは、データの作成、更新、削除など、書き込み操作を定義するために使用されます。以下の例では、新しい本を追加するミューテーションを定義しています。
type Mutation {
  createBook(input: CreateBookInput): Book
}
mutation {
  createBook(input: {title: "GraphQL入門", author: "xxxxx"}) {
    id
    title
  }
}
Subscription
Subscriptionは、GraphQLで定義された一種の操作であり、クライアントがサーバーからリアルタイムのデータ更新を購読するために使用されます。これは、WebSocketsなどの持続的な接続を通じて実装されることが多く、特にチャットアプリケーションやリアルタイムの通知システムで使用されます。
以下は、書籍の追加をリアルタイムで購読する簡単な例です。
type Subscription {
  bookAdded: Book
}
subscription {
  bookAdded {
    id
    title
    author
  }
}
この例では、新しい書籍が追加されるたびに、**bookAdded**サブスクリプションを通じてその書籍の情報が購読者にプッシュされる構成になっています。これにより、アプリケーションはリアルタイムに新しい書籍の追加をユーザーに通知することができます。
Variables
クエリやミューテーション内で変数を使用することで、クエリの再利用性を高めることができます。変数は$記号で始まります。
mutation CreateBook($input: CreateBookInput!) {
  createBook(input: $input) {
    id
    title
  }
}
Fragment
Fragment は、複数のクエリやミューテーションで再利用可能なフィールドの集合を定義するために使用します。これにより、クエリの複雑さを減らすことができます。
fragment BookDetails on Book {
  id
  title
  author
}
query {
  books {
    ...BookDetails
  }
}
まとめ
この記事を通じて、GraphQLの基本概念、スキーマ定義、タイプシステム、さらには操作タイプ(クエリ、ミューテーション、サブスクリプション)、変数の使用、フラグメントの利用など、GraphQLの中核となる構文について概観しました。これらの内容をまとめることで、GraphQLに関する理解が一層深まりました。

