Slide 1

Slide 1 text

今こそ思い出す GraphQLの特徴 tsukiji.graphql x ハッカー鮨 2024/04/19 ham

Slide 2

Slide 2 text

開発⽣産性が向上する⽅法を探求しているエンジニア! Ruby / Rails / React / TypeScript / AWS Agile / DevOps / Developer Productivity / DevEx Stock Investment 浜⽥ 直⼈ Naoto Hamada (ham) @hamchance0215

Slide 3

Slide 3 text

はじめに 最近、GraphQLの認知度が上がってきたことで、GraphQLの特徴を抑えずに雰囲 気で使っているケースが増えてきていると感じます。 本発表では、改めてGraphQLの特徴を復習することでGraphQLの特徴を把握し て、ポテンシャルを引き出せるようにしたいと思います。

Slide 4

Slide 4 text

必要なフィールドのみ取得

Slide 5

Slide 5 text

user(id:$id) { id name createdAt updatedAt } 必要なフィールドのみ取得 - 呼び出し元ではnameしか使わない

Slide 6

Slide 6 text

user(id:$id) { id name } 必要なフィールドのみ取得 - 呼び出し元ではnameしか使わない - 使うフィールドのみ指定 - 例外としてidフィールドは後に説明する キャッシュのキーとして使⽤するのでキャッ シュを活⽤するなら取得すべき

Slide 7

Slide 7 text

無駄な処理

Slide 8

Slide 8 text

user(id:$id) { id reviewCount } 無駄な計算 # Ruby code def resolve(id:) user = User.find_by(id:) { id: user.id, review_count: user.reviews.count, } end

Slide 9

Slide 9 text

user(id:$id) { id reviewCount } 無駄な計算 – users select * from users where id = 1; – reviews select count(*) from reviews where user_id = 1;

Slide 10

Slide 10 text

user(id:$id) { id } 無駄な計算 – reviewCountを指定していなくても reviews.countが計算される # Ruby code def resolve(id:) user = User.find_by(id:) { id: user.id, review_count: user.reviews.count, } end

Slide 11

Slide 11 text

user(id:$id) { id } 無駄な計算 – reviewCountを指定していなくても reviews.countが計算される # Ruby code def resolve(id:) User.find_by(id:) end # Userモデルのメソッドとして提供して呼ばれ たときだけ取得する def review_count reviews.count end

Slide 12

Slide 12 text

遅延ロード

Slide 13

Slide 13 text

users { id profile { name } } 遅延ロード – id fieldはusersテーブルから取得 – profileはprofilesテーブルから取得 # Ruby code def resolve User.all end

Slide 14

Slide 14 text

users { id profile { name } } 遅延ロード – usersは10件Hit select * from users; – profilesを1件ずつ取得 => N+1問題 select * from profiles where user_id = 1; select * from profiles where user_id = 2; … select * from profiles where user_id = 10;

Slide 15

Slide 15 text

users { id profile { name } } 遅延ロード – usersに対応するprofileを事前ロード # Ruby code def resolve User.all.preload(:profile) end

Slide 16

Slide 16 text

users { id profile { name } } 遅延ロード – usersは10件Hit select * from users; – hitしたusersに対応したprofilesを事前ロード select * from profiles where user_id in (1, 2, …, 10);

Slide 17

Slide 17 text

users { id } 遅延ロード – usersは10件Hit select * from users; – fieldに指定していなくてもprofilesを事前ロー ドしてしまう select * from profiles where user_id in (1, 2, …, 10);

Slide 18

Slide 18 text

users { id profile { name } } 遅延ロード – usersに対応するprofileを遅延ロード # Ruby code def resolve # fieldにprofileがある場合、profile を取得するuser_idを記憶しておき、最後にま とめて取得する User.all end

Slide 19

Slide 19 text

キャッシュの活⽤

Slide 20

Slide 20 text

user(id:$id) { __typename id name } キャッシュの活用 - キャッシュを活⽤することで1度取得した データはバックエンドに問い合わせずに瞬時 に表⽰できる - ※APOLLOの場合 - https://www.apollographql.com/docs/react/data/ mutations - `__typename`と`id`でデータをキャッシュ

Slide 21

Slide 21 text

mutation UpdateUser(input:UpdateUserInput!) { updateUser(input:$input) { id name } } - Mutationのレスポンスで変更後の値を受け取ることで、キャッシュが更 新される - 明示的にrefetchしなくてもOK キャッシュの活用

Slide 22

Slide 22 text

まとめ

Slide 23

Slide 23 text

まとめ - 必要なフィールドのみ取得しよう - 指定していないフィールドの値は取得しない - N+1対策は遅延ロード - キャッシュを有効活用しよう