Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Revisiting GraphQL in the RSC Era, and Co- Loca...

Revisiting GraphQL in the RSC Era, and Co- Located GraphQL Backend Inside Next.js (ja)

Avatar for Kenta Kudo

Kenta Kudo

January 27, 2026

More Decks by Kenta Kudo

Other Decks in Programming

Transcript

  1. #LT #GraphQL #Next.js #RouteHandlers #RSC Revisiting GraphQL in the RSC

    Era, and Co- Located GraphQL Backend Inside Next.js Kenta Kudo - Freelance Software Engineer React Osaka - Jan 2026 1
  2. 1. 導入 — 「GraphQLはまだ必要?」 React Server Componentの時代 RSCはコンポーネント単位でのサーバー側データ取得を可能にする RSC以前は... Next.jsのPages

    Routerはページ単位のデータ取得 1回のクエリでデータをまとめて取得 最近の主張: 「RSCではGraphQLは不要になりつつある」 気づき GraphQLの価値は「一括取得」だけではない 型安全性 + DXの点で依然有用 6
  3. 2. GraphQLの再発見 — 素直なクエリ グラフ構造 query GetUserWithPosts($id: ID!) { user(id:

    $id) { name posts { title content } } } グラフとしてリソースを問い合わせ、関係を辿れる スキーマ/イントロスペクション(有効時)+ GraphiQLなどのツールによる発見性 新しいエンドポイントなしで柔軟に選択 エンドポイントではなくノードの関係を辿る 7
  4. 2. GraphQLの再発見 — 使いやすいmutation GraphQL mutation UpdatePostTitle($id: ID!, $title: String!)

    { updatePostTitle(id: $id, title: $title) { post { id title } } } 利点: RPC風のミューテーションで意図が明確 ビジネスロジックがインターフェース上に現れる 型付き引数、発見性、一貫したエルゴノミクス 9
  5. 3. 同居型バックエンド構成 — Route Handlers Next.jsのRoute Handlers サーバー側で実行され、バックエンドAPIのようにアクセス可能 App Router

    → Route Handlers Pages Router → API Routes 増えている潮流 Route Handlersを使い別バックエンドなしでNext.jsアプリを構築 10
  6. 3. 同居型バックエンド構成 — Route Handlers テンプレート GitHubリポジトリテンプレート: GraphQL + Route

    Handlers https://github.com/KentaKudo/next-graphql-handler 注: このテンプレートは概念のデモ用です。本番向けには認証やエラーハンドリング 等が必要です。 11
  7. 3. 同居型バックエンド構成 — Route Handlers /api/graphql/route.ts import { createYoga }

    from "graphql-yoga"; import { schema } from "./schema"; const { handleRequest } = createYoga({ graphqlEndpoint: "/api/graphql", fetchAPI: { Response }, schema, }); export { handleRequest as GET, handleRequest as POST }; Apollo Serverなら → @as-integrations/next 12
  8. 3. 同居型バックエンド構成 — クライアント側 urqlクライアント設定(Server Components) // lib/urql.ts import {

    cacheExchange, createClient, fetchExchange } from "@urql/core"; import { registerUrql } from "@urql/next/rsc"; const makeClient = () => createClient({ url: "http://localhost:3000/api/graphql", exchanges: [cacheExchange, fetchExchange], }); export const { getClient } = registerUrql(makeClient); 14
  9. 3. 同居型バックエンド構成 — クライアント側 例: Server Component import { graphql

    } from "@/graphql"; import { getClient } from "@/lib/urql"; const helloQuery = graphql(` query Hello { hello(name: "from server component") } `); export default async function Home() { const result = await getClient().query(helloQuery, {}).toPromise(); if (result.error) { return <div>Error: {result.error.message}</div>; } return <div>Hello: {result.data?.hello}</div>; } 15
  10. 3. 同居型バックエンド構成 — クライアント側 urqlクライアント設定(Client Components) // app/providers/urql.tsx "use client";

    import type { ReactNode } from "react"; import { createClient, UrqlProvider as NextUrqlProvider } from "@urql/next"; import { cacheExchange, fetchExchange } from "@urql/core"; const client = createClient({ url: "/api/graphql", exchanges: [cacheExchange, fetchExchange], }); export const UrqlProvider = ({ children }: { children: ReactNode }) => ( <NextUrqlProvider value={client}>{children}</NextUrqlProvider> ); 16
  11. 3. 同居型バックエンド構成 — クライアント側 例: Client Component "use client"; import

    { graphql } from "@/graphql"; import { useQuery } from "@urql/next"; const helloQuery = graphql(` query HelloFromClientComponent { hello(name: "from client component") } `); export const ClientComponent = () => { const [result] = useQuery({ query: helloQuery }); if (result.error) { return <div>Error: {result.error.message}</div>; } return <div>ClientComponent: {result.data?.hello}</div>; }; 17
  12. 4. まとめ — GraphQLがまだ輝く時 RSC + BFFパターン RSCで同居型取得が可能になっても、次の価値は残る: 型付きで見通しの良いスキーマ(GraphQL) 強力な組み合わせ:

    柔軟なグラフクエリ & 使いやすいミューテーション(RPC風) 同居型アーキテクチャ: Next.js + GraphQL + Route Handlers 結論 RSCは どこで 取得するかを変えるだけで、そのインターフェイスが どうあるべきか は変えない 18
  13. 参考資料 おすすめ: Black Hat GraphQL https://nostarch.com/black-hat-graphql 高コストなクエリによるDoS(深いネスト) 認可の落とし穴(フィールド単位のチェック漏れ) 情報漏洩(本番でのイントロスペクション) テンプレートリポジトリ

    https://github.com/KentaKudo/next-graphql-handler 世界で働くエンジニア Book: https://store.london-tech- talk.com/products/book_engineers_working_abroad London Tech Talk Podcast: https://london-tech-talk.com/ 19
  14. 付録: Code-first vs Schema-first コードファースト コードベースからGraphQLスキーマを生成 → コードが真実のソース 選ぶとき: TypeScriptモノレポでDXが良い

    スキーマファースト スキーマを書いて、リゾルバの骨組みを生成 → スキーマが真実のソース 選ぶとき: 言語横断チーム / スキーマガバナンス 私の好み: Pothosのコードファースト テンプレートはPothos GraphQLでコードファーストを採用 22
  15. 付録: Pothosでのコードファースト例 import SchemaBuilder from "@pothos/core"; const builder = new

    SchemaBuilder({}); builder.queryType({ fields: (t) => ({ hello: t.string({ args: { name: t.arg.string() }, resolve: (parent, { name }) => `hello, ${name || "World"}`, }), }), }); export const schema = builder.toSchema(); 型安全で簡潔、TypeScriptネイティブ 23
  16. 付録: 本番運用の注意点 — GraphQLは強力、守るべ き セキュリティと性能 認可: フィールド単位の認可(ルート単位だけでなく) N+1対策: バッチング

    / DataLoaderパターン クエリ複雑度: 深さ・コスト制限 イントロスペクション: 本番では無効化(または制限) エラーマスキング: 内部エラーを漏らさない レート制限: 乱用対策 24