📚

ChatGPTにGraphQLの概要を教えてもらった

2024/08/04に公開

GraphQLについて素人の僕がChatGPTに聞きながらGraphQLについて学んだことをまとめてみました。

なお、この記事はChatGPTが作成した文章をそのまま掲載したものではありません。何回も質問しながら疑問点を解消し、それらを再構成、加筆、修正したものとなっています。

GraphQLとは何か

  • GraphQLは、Facebookが開発したクエリ言語で、APIのデータ取得と操作を効率化します。
  • クライアントが必要なデータを具体的に指定できるため、過剰なデータ取得や不足を防ぎます。
  • REST APIに比べて柔軟性が高く、単一エンドポイントで複数のリソースを取得可能です。
  • 型システムを持ち、クエリのバリデーションが可能で、開発者が迅速にエラーを検出できます。
  • これにより、フロントエンドとバックエンドの開発がスムーズに進むことが期待できます。

GraphQLの簡単な例

以下に、GraphQLの具体的な例を示します。

スキーマ定義

type Query {
  user(id: ID!): User
}

type User {
  id: ID
  name: String
  email: String
}

クエリ例

query {
  user(id: "1") {
    name
    email
  }
}

レスポンス例

{
  "data": {
    "user": {
      "name": "John Doe",
      "email": "john.doe@example.com"
    }
  }
}

この例では、userというクエリで特定のユーザー(id=1)のnameとemailを取得しています。クエリで指定されたフィールドのみがレスポンスとして返されるため、必要なデータだけを効率よく取得できます。
クエリのレスポンスには必ずdataフィールドが含まれます。

スキーマ定義とは何か

  • スキーマ定義は、GraphQLで使用されるデータ型とフィールドの定義を含む設計ドキュメントです。
  • このスキーマには、クエリ(データの取得)、ミューテーション(データの変更)、サブスクリプション(リアルタイムデータの受信)のためのエントリーポイントやデータ構造が含まれます。
  • スキーマ定義によって、GraphQLサーバーとクライアントがデータの形式や通信方法を共有し、効率的なデータ取得と操作を実現できます。

なお、スキーマ定義はサーバー側で定義されます。GraphQLでは、サーバーがスキーマを提供し、クライアントはそのスキーマに基づいてクエリを構築します。

スキーマ定義では、クライアントがどのようなデータを要求できるかや、どのようなデータを変更できるかを定義します。クライアントはスキーマを参照して適切なクエリを構築し、サーバーに送信します。

スキーマ定義の具体例

スキーマ定義では、「データ型定義」と「エントリーポイント定義」「入力型定義」などの要素で構成されます。

データ型定義

その名の通りデータ型を定義します。たとえば、UserやPostなどのオブジェクト型を定義できます。各オブジェクト型はフィールドを持ち、それぞれのフィールドには型が指定されます。

type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String!
}

エントリーポイント定義

スキーマでは、クエリ、ミューテーション、サブスクリプションのエントリーポイントを定義します。これにより、クライアントがデータを取得したり、変更したり、リアルタイムデータを購読したりできます。

type Query {
  getUser(id: ID!): User
  getPost(id: ID!): Post
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updatePost(id: ID!, input: UpdatePostInput!): Post!
}

type Subscription {
  postUpdated: Post!
}

getUser(id: ID!)では、idをパラメーターで受け取り、idに一致したUserを返すクエリです。どんなパラメーターが使えるのかは、スキーマ定義とサーバー側の実装によります。

先頭n個のデータを取得するとか、なんらかの条件でフィルタリングするとか、並べ替え指定をするとか、いろんなパラメーターが考えられます。

入力型定義

ミューテーションや一部のクエリで使用する入力データの型を定義します。これにより、クライアントがデータをサーバーに送信する際の形式を明示します。

input CreateUserInput {
  name: String!
  email: String!
}

input UpdatePostInput {
  title: String
  content: String
}

なお、この記事では、クエリに焦点をあてたいので、ミューテーション、サブスクリプションについては、これ以上深入りしません。

スキーマ定義の利点

以下のような利点があります。

明確なデータ構造

スキーマ定義により、データ構造が明確になります。クライアントとサーバーは共通のデータモデルを持ち、通信が効率的になります。

バリデーション

スキーマはクエリやミューテーションのバリデーションに役立ちます。クライアントが不正なクエリを送信したり、不正なデータを更新しようとしたりすると、エラーが発生します。

ドキュメント化

スキーマはAPIのドキュメントとしても機能します。開発者はスキーマを参照して利用可能なエンドポイントやデータ型を把握できます。

柔軟性と拡張性

スキーマは柔軟であり、新しいフィールドやエンドポイントを追加する際に簡単に拡張できます。これにより、アプリケーションの要件が変更された場合でも、スキーマを更新することで対応できます。

GraphQLのデータ型

GraphQLでは、次のような主要なスカラー型(Scalar Types)があります。

説明
Int 整数型。たとえば、42や-10などが該当します。
Float 浮動小数点数型。たとえば、3.14や-0.5などが該当します。
String 文字列型。たとえば、"Hello"や"GraphQL"などが該当します。
Boolean 真偽値型。trueまたはfalseを表します。
ID ユニークな識別子を表す特別な文字列型。主にデータの識別に使用されます。

これらのスカラー型は、GraphQLの基本的なデータ型として使われます。また、リスト型(List Types)や非null型(Non-Null Types)といった、型を組み合わせてより複雑なデータ構造を定義することもできます。

非null型

先ほどのスキーマ定義の例で ID! という記述がありましたが、ID!は、GraphQLにおける型指定の一種です。!はそのフィールドが必須であることを示します。

具体的には、IDは一意の識別子を表し、通常はUUIDやデータベースのキーなどが使われます。!はnullを許容しないことを意味します。つまり、そのフィールドは必ず値を持たなければならないという意味です。

たとえば、次のようなスキーマ定義があるとします。

type User {
  id: ID!
  name: String!
  email: String!
}

この定義では、User型のすべてのフィールドは必須であり、nullを許容しません。

型はすべて大文字で始まるのか?

GraphQLにおいて、型は大文字で始まる必要はありません。一般的に、型(Type)やフィールド(Field)といったGraphQLのキーワードは、大文字で始まることが多いですが、必須ではありません。

ただし、多くの開発者やドキュメントでは、型やフィールドを大文字で始めることが一般的であり、可読性の観点から推奨されます。

クエリの具体例(1)

スキーマ定義

以下のようなスキーマが定義されていたとします。

type Query {
  Product(id: ID!): Product
  AllProducts: [Product!]!
}

このスキーマ定義をつかったサーバー側の実装は、ここでは省略します。
この例では、Query型には2つのフィールドがあります。

Product(id: ID!): Product

特定の商品を取得するためのクエリです。idパラメーターで商品IDを指定し、Product型のオブジェクトを返します。

AllProducts: [Product!]!

すべての商品を取得するためのクエリです。戻り値としてProduct型のリストを返します。リスト内の各商品はnullを許容しません。

Product型の定義を示します。

type Product {
  id: ID!
  name: String!
  price: Float!
  description: String
}

Product型は、商品の情報を表現するためのオブジェクト型です。idは識別子、nameは商品名、priceは価格(浮動小数点数)、descriptionは商品の説明を表します。

クエリの例

では、このスキーマに対して、どんなクエリが使えるかその例を示します。

特定の商品を取得する

{
  Product(id: "1") {
    id
    name
    price
    description
  }
}

このクエリは、IDが"1"の商品の詳細情報(ID、名前、価格、説明)を取得します。

すべての商品を取得する

{
  AllProducts {
    id
    name
    price
  }
}

このクエリは、すべての商品の詳細情報(ID、名前、価格)をリストで取得します。Descriptionは指定から除外しています。クライントで必要のないデータは、このようにクエリから除外することができます。

クエリの具体例(2)

最初のほうで示した以下のスキーマ定義とデータ型のクエリについて考えてみます。

type Query {
  getUser(id: ID!): User
  getPost(id: ID!): Post
}

type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String!
}

クエリの例

以下に、ユーザー情報を取得する基本的なクエリの例を示します。

{
  getUser(id: "1") {
    id
    name
    email
  }
}

このクエリは、IDが1のユーザーのID、名前、メールアドレスを取得します。
以下のようなJSONが返ります。

{
  "data": {
    "user": {
      "id": "1",
      "name": "John Doe",
      "email": "john.doe@example.com",
    }
  }
}

データをネストされたデータとして取得することもできます。

{
  user(id: "1") {
    id
    name
    email
    posts {
      id
      title
      content
    }
  }
}

このクエリは、IDが1のユーザーの情報に加えて、そのユーザーが書いた投稿のID、タイトル、コンテンツを取得します。
以下のようなJSONが返ります。

{
  "data": {
    "user": {
      "id": "1",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "posts": [
        {
          "id": "101",
          "title": "Post 1",
          "content": "Content of post 1"
        },
        {
          "id": "102",
          "title": "Post 2",
          "content": "Content of post 2"
        }
      ]
    }
  }
}

おわりに

GraphQLの基本的なクエリは、必要なデータを効率的に取得するために設計されています。フィールドを明示的に選択し、必要なデータだけを取得することで、ネットワークの負荷を軽減し、効率的なデータ取得が可能になります。
初心者としては、これらの基本的なクエリ構造を理解することから始めると良いでしょう。

今回、初めてGraphQLについて調べたのですが、ChatGPTに質問することで、GraphQLってなんなのかがおおよそ理解できました。ChatGPTやっぱりすごいですね。

この記事は、GraphQLの知識がない僕がChatGPTに聞きながら書いたものなので、間違っている箇所があるかもしれません。気がついた方はコメント等でご指摘いただけるとありがたいです。

GitHubで編集を提案
株式会社ジード テックブログ

Discussion