読書メモ:初めてのGraphQL

2024/09/28

3年くらい前に一度読書会で読みましたが、再度「初めてのGraphQL 」を読んだのでメモです。

1章 GraphQLへようこそ

  • GraphQL は API のための問い合わせ言語
    • クエリを実行してデータを呼び出すためのランタイムを指すこともある
  • クエリが入れ子になっている場合は、実行時に関連するオブジェクトを全て探し出す
    • つまり、1回の HTTP リクエストで2つの異なる種類のデータを受け取ることができる。そのため、レスポンスデータを使ってさらにリクエストを送るみたいな冗長的な設計をしなくて済む
  • GraphQL の設計原則
    • 階層構造、プロダクト中心、強い型付け、クライアント毎のクエリ、自己参照
  • REST の課題
    • 過剰な取得 -> レスポンスによって、大きいリクエストや不要なデータが含まれる。GraphQL ではフィールドを絞れるため要求したデータのレスポンスを取得できる
    • 自由度の低さ -> クライアントに変更が加わると新しいエンドポイントを作成する必要あり。開発速度の鈍化に繋がり、設計によっては似たような API を作る必要あり。GraphQL は単一のエンドポイント構成されている
    • つまりステータスコードも統一。セオリーは 200 。この辺りは REST と違っている点で、エラーレスポンスは工夫する必要あり。(書籍にはこの辺りは書いていなかった...)

2章 グラフ理論

  • グラフ理論の話
  • グラフは相互に接続されたオブジェクトの集合を形式的に表現するために使われる
    • CS の分野ではグラフはデータのネットワークを表すために使われてきた
  • グラフを数学的な表現をすると G = (V, E)
    • G はグラフを意味し、V と E はそれぞれ頂点 (Vertext) エッジ (Edge) の集合
  • 図がないとイメージしづらいので割愛 (Wiki がわかりやすかった)

3章 GraphQLの問い合わせ言語

  • GraphQL のクエリの話
  • query は GraphQL の型の一つでルート型
    • ルート型はオペレーションに対応する GraphQL の型で、入れ子になっているクエリドキュメントの一番上位にはルートが型指定される
    • 波括弧で囲まれたブロックは選択セットと呼ばれる。選択セットで指定できるフィールドは GraphQL の型に基づく
    • liftCount、allLifts、allTrails の3つのフィールドは Query 型のフィールドとして定義される
query liftsAndTrails {
  liftCount(status: OPEN)
  allLifts: {
    name
    status
  }
  allTrails {
    name
    difficulty
  }
}
  • フラグメントの話
    • フラグメントは複数の場所で使いまわせる選択セット
    • ざっくり以下のように書く。利点として、さまざまなクエリで使用されている選択セットの変更が一つのフラグメントの修正で済むこと
query {
  allTrails {
    ...trailStatus
    ...trailDetails
  }
}

fragment trailStatus on Trail {
  name
  status
}

fragment trailDetails on Trail {
  groomed
  night
}
  • ミューテーションの話
    • クエリは読み込み、ミューテーションは書き込みを担当する
    • ざっくり以下のように書く。mutation はルート型。選択できるフィールドも API スキーマで定義されている
    • 引数にはクエリ変数を使って動的な値でミューテーションすることもできる
mutation createSong($title:String!, $numberOne: Int) {
  addSong(title:$title, numberOne:$numberOne) {
    id
    title
    numberOne
  }
}

4章 スキーマの設計

  • スキーマ設計の話。設計原則である強い型付けを実現する
  • API は REST のエンドポイントの集合ではなく、型の集合として捉えられる
    • データ型の集合をスキーマと呼ぶ
  • 型を簡単に定義できるように、GraphQL はスキーマを定義するための言語を用意している -> スキーマ定義言語 (SDL)
type Photo {
  ID!
  name: String!
  url: String!
  description: String
}
  • Enum
    • あらかじめ定められた特定の文字列を返すスカラー型
    • 限られた選択肢のうちの一つの値を返すフィールドを実装したい時に使う
enum PhotoCategory {
  SELFIE
  ACTION
}

type Photo {
  id: ID!
  category: PhotoCategory!
}
  • コネクションとリスト
    • 型のリスト。[String]はString型のリストを表す
  • リストとnull制約
[Int]
[Int!]
[Int]!
[Int!]!
  • リレーション
    • カスタムオブジェクト型のフィールドを定義して実現
// 1:1
type User {
  name String
  avatar: String
}

type Photo {
  // more
  postedBy: User!
}

// 1:type User {
  // more
  postedPhotos: [Photo!]!
}

// 多対多
type User {
  // more
  inPhotos: [Photo!]!
}

type Photo {
  taggedUsers: [User!]!
}

5章 GraphQLサーバーの実装

  • Express + Apollo serverのチュートリアル
  • MongoDB の接続や GitHub OAuth による認証と認可の説明もあり参考になりそうだった

6章 GraphQLクライアントの実装

  • この辺りは実際にサーバーサイドから受け取って Apollo でデータを扱うチュートリアル。apollo-boost と react-apollo すでに非推奨なので、@apollo/client を使う

  • キャッシュ周りもできるので便利 (ただ最近は graphql-request と Tanstack Query や SWR を使うのが主流か・・・?)

7章 GraphQLの実戦投入にあたって

  • サブスクリプションとファイルアップロードの話

最後に

久々初めての GraphQL を読んでみました。全7章で構成されていて、個人的に GraphQL を思い出すのに読みやすくて一番いい書籍だと感じます。しかし、発行年月日が2019年11月なので注意が必要です。GraphQL の公式仕様が書いてある GraphQL Specification を読んで、新しい仕様キャッチアップするのも重要です。