GraphQL Yoga 模式指南
快速指南: 使用
createYoga+createSchema建立一個相容 Fetch API 的 GraphQL 伺服器,可在任何 JS 執行環境中運行。Yoga v5 使用 Envelop 進行插件組合,預設使用 SSE 進行訂閱,內建錯誤遮罩和 CORS 支援。請從graphql(而非graphql-yoga)匯入GraphQLError,以用於有意的客戶端錯誤。在 HTTP 層級的優化方面,優先使用 Yoga 特定的插件而非 Envelop 等效插件。
<critical_requirements>
關鍵:使用此技能前
所有程式碼必須遵循 CLAUDE.md 中的專案慣例(kebab-case、具名匯出、匯入順序、
import type、具名常數)
(你必須從 'graphql' 匯入 GraphQLError,而不是從 'graphql-yoga' —— 這是標準的 graphql-js 匯出)
(你必須優先使用 Yoga 特定插件而非 Envelop 等效插件 —— Yoga 插件在 HTTP 層運作,可以為快取/持久化的結果完全跳過 GraphQL 執行)
(你必須使用 createSchema 從 'graphql-yoga' 進行 schema-first 開發 —— 在 v5 中,不支援將原始的 typeDefs/resolvers 物件直接傳遞給 createYoga)
(你必須為所有數值使用具名常數 —— 逾時、TTL、連接埠號碼、限制)
</critical_requirements>
自動偵測: GraphQL Yoga, graphql-yoga, createYoga, createSchema, createPubSub, Envelop, useResponseCache, useCSRFPrevention, usePersistedOperations, GraphQL subscriptions SSE, error masking, maskedErrors, graphql-ws, Yoga plugin hooks, onRequest, onParams
使用時機:
- 建立需要在 Node.js、Bun、Deno 或 Cloudflare Workers 上運行的 GraphQL 伺服器
- 需要透過 SSE(預設)或 WebSocket 進行訂閱的 API
- 使用 Envelop 插件(快取、認證、日誌)擴展 GraphQL 執行
- 使用 GraphQL Multipart Request 規範進行檔案上傳
- 需要錯誤遮罩、CORS 和 CSRF 保護的正式環境 API
不應使用時機:
- 僅使用 REST 且無 GraphQL 需求的 API
- 簡單的 CRUD 操作,框架的內建路由處理器就足夠
- 需要聯邦網關時(請考慮專用的網關解決方案)
涵蓋的主要模式:
- 使用
createYoga和createSchema進行伺服器設定(schema-first) - 在
createYoga<ServerContext>上使用泛型進行型別安全的 context - Envelop 插件系統:生命週期鉤子、自訂插件、Yoga 特定插件
- 訂閱:SSE(預設)、透過
graphql-ws的 WebSocket、內建 PubSub - 錯誤遮罩與有意的
GraphQLError暴露 - 使用 WHATWG
File標量進行檔案上傳 - 生產環境強化:CORS、CSRF 預防、GraphQL Armor、日誌
- 跨執行環境部署:Node.js、Bun、Deno、Cloudflare Workers
詳細資源:
- examples/core.md - 伺服器設定、schema、context、解析器、跨執行環境部署
- examples/plugins.md - Envelop 插件、自訂插件、生命週期鉤子
- examples/subscriptions.md - SSE、WebSocket、PubSub、過濾
- examples/error-handling.md - 錯誤遮罩、GraphQLError、自訂遮罩
- examples/production.md - CORS、CSRF、回應快取、持久化作業、日誌
- reference.md - 決策框架、插件參考、生產環境檢查清單
理念
GraphQL Yoga 是一個 功能齊全、相容 Fetch API 的 GraphQL 伺服器。其核心建構於 WHATWG Fetch API(Request/Response)之上,使其與執行環境無關 —— 相同的伺服器程式碼可部署到 Node.js、Bun、Deno 和邊緣執行環境。Envelop 插件系統在 HTTP 和 GraphQL 執行層都提供了可組合的中介軟體。
Schema 方法: Yoga 與 schema 函式庫無關。使用 createSchema(schema-first SDL)、Pothos(code-first)或純粹的 graphql-js —— 任何能產生 GraphQLSchema 的方法都可以。
插件優先級: 當同一個功能(快取、持久化作業、defer/stream)同時存在 Envelop 插件和 Yoga 特定插件時,始終選擇 Yoga 變體。Yoga 插件掛鉤到 HTTP 層,可以在 GraphQL 執行開始之前短路,完全跳過快取或持久化結果的解析和驗證。
錯誤理念: 在生產環境中,所有非預期的錯誤預設都會被遮罩。有意的錯誤會以 GraphQLError 的形式從 graphql 套件中拋出 —— 這些錯誤會繞過遮罩,並將其訊息和 extensions 完整地送達客戶端。
核心模式
模式 1:使用 createYoga 進行伺服器設定
使用 createSchema 為基於 SDL 的 schema 建立一個 Yoga 實例。yoga 實例本身就是一個 Fetch API 處理器 —— 將其直接傳遞給任何執行環境的 HTTP 伺服器。
import { createYoga, createSchema } from "graphql-yoga";
import { createServer } from "node:http";
const PORT = 4000;
const yoga = createYoga({
schema: createSchema({
typeDefs: /* GraphQL */ `
type Query {
greeting(name: String!): String!
}
`,
resolvers: {
Query: {
greeting: (_, { name }) => `Hello, ${name}!`,
},
},
}),
});
const server = createServer(yoga);
server.listen(PORT, () => {
console.info(`Server running on http://localhost:${PORT}/graphql`);
});
優點: createSchema 封裝了 makeExecutableSchema,yoga 實例是標準的 Fetch 處理器,可在任何執行環境中運作
請參閱 examples/core.md 以了解完整的設定、跨執行環境部署和型別安全 context。
模式 2:型別安全 Context
為 createYoga 傳遞泛型以進行伺服器特定的 context 型別化。context 工廠接收 YogaInitialContext(包含 request 和 params)並回傳你的自訂 context。
import { createYoga, type YogaInitialContext } from "graphql-yoga";
interface ServerContext {
req: IncomingMessage;
res: ServerResponse;
}
const yoga = createYoga<ServerContext>({
schema,
context: async ({ request }: YogaInitialContext) => {
const token = request.headers.get("authorization");
return { user: token ? await verifyToken(token) : null };
},
});
優點: 泛型型別流向解析器的 context 參數,request 使用標準的 Fetch API(而非框架特定的 req/res)
請參閱 examples/core.md 以了解完整的 context 模式。
模式 3:Envelop 插件系統
插件透過 plugins 陣列傳遞。當有可用的 Yoga 特定插件時,請使用它們 —— 它們在 HTTP 層運作,可以完全跳過 GraphQL 執行。
import { createYoga } from "graphql-yoga";
import { useResponseCache } from "@graphql-yoga/plugin-response-cache";
const CACHE_TTL_MS = 2_000;
const yoga = createYoga({
schema,
plugins: [
useResponseCache({
session: () => null,
ttl: CACHE_TTL_MS,
}),
],
});
優點: Yoga 回應快取會跳過快取結果的解析/驗證(Envelop 等效插件無法做到),插件組合時不會發生衝突
請參閱 examples/plugins.md 以了解自訂插件、生命週期鉤子和所有 Yoga 特定插件。
模式 4:使用 SSE 進行訂閱(預設)
Yoga 預設使用 Server-Sent Events 進行訂閱 —— 不需要 WebSocket 設定。在訂閱解析器中使用 AsyncGenerator 語法。
const schema = createSchema({
typeDefs: /* GraphQL */ `
type Subscription {
countdown(from: Int!): Int!
}
`,
resolvers: {
Subscription: {
countdown: {
subscribe: async function* (_, { from }) {
for (let i = from; i >= 0; i--) {
await new Promise((resolve) => setTimeout(resolve, 1_000));
yield { countdown: i };
}
},
},
},
},
});
優點: 不需要 WebSocket 基礎設施,可透過 HTTP 代理和負載平衡器運作,客戶端使用 graphql-sse 函式庫
請參閱 examples/subscriptions.md 以了解 PubSub、WebSocket 設定和過濾。
模式 5:錯誤遮罩與 GraphQLError
Yoga 預設會遮罩所有非預期的錯誤。對於有意的客戶端錯誤,請拋出 GraphQLError(來自 graphql)—— 這些錯誤會繞過遮罩。
import { GraphQLError } from "graphql";
const NOT_FOUND_CODE = "USER_NOT_FOUND";
throw new GraphQLError("User not found", {
extensions: { code: NOT_FOUND_CODE },
});
優點: 非預期的錯誤永遠不會洩漏內部資訊(資料庫細節、堆疊追蹤),有意的錯誤會連同訊息和 extensions 一起通過
請參閱 examples/error-handling.md 以了解自訂遮罩、停用遮罩和開發模式。
模式 6:檔案上傳
Yoga 支援 GraphQL Multipart Request 規範。加入 File 標量,並在解析器中接收 WHATWG File 物件。
const schema = createSchema({
typeDefs: /* GraphQL */ `
scalar File
type Mutation {
uploadFile(file: File!): Boolean!
}
`,
resolvers: {
Mutation: {
uploadFile: async (_, { file }: { file: File }) => {
const content = await file.arrayBuffer();
// Process file content
return true;
},
},
},
});
優點: 使用標準的 WHATWG File API(與瀏覽器相同),不需要額外套件,可使用 multipart: false 停用
請參閱 examples/core.md 以了解完整的檔案上傳模式。
<decision_framework>
決策框架
Schema 方法
需要從 SDL 自動產生型別?
+-- 是 --> createSchema(schema-first,使用 typeDefs + resolvers)
+-- 否 --> 需要在 schema 定義中進行完整的 TypeScript 推論?
+-- 是 --> Code-first 函式庫(例如 Pothos)—— 將產生的 GraphQLSchema 傳遞給 Yoga
+-- 否 --> 原生的 graphql-js GraphQLSchema
訂閱傳輸
需要訂閱?
+-- 是 --> 客戶端需要雙向通訊?
| +-- 是 --> 透過 graphql-ws 使用 WebSocket(安裝 ws + graphql-ws 套件)
| +-- 否 --> SSE(預設,無需設定,可透過代理運作)
+-- 否 --> 不需要訂閱設定
插件選擇
該功能是否有 Yoga 特定插件可用?
+-- 是 --> 使用 Yoga 插件(HTTP 層級鉤子,可以跳過執行)
+-- 否 --> 使用 Envelop 插件(GraphQL 執行層級鉤子)
Yoga 特定插件(優先於 Envelop)
| 插件 | 套件 | 為何選擇 Yoga 特定 |
|---|---|---|
| Response Cache | @graphql-yoga/plugin-response-cache | 跳過快取查詢的執行 |
| Persisted Operations | @graphql-yoga/plugin-persisted-operations | 在 HTTP 層拒絕未知操作 |
| Defer/Stream | @graphql-yoga/plugin-defer-stream | 透過 HTTP chunked encoding 串流 |
| CSRF Prevention | @graphql-yoga/plugin-csrf-prevention | 在解析前要求自訂標頭 |
| GraphQL SSE | @graphql-yoga/plugin-graphql-sse | 單一連線 SSE 模式 |
</decision_framework>
<red_flags>
紅旗警示
高優先級:
- 從
graphql-yoga而非graphql匯入GraphQLError—— 錯誤的套件,將會失敗 - 將
typeDefs/resolvers物件直接傳遞給createYoga而未使用createSchema—— v5 不支援此用法 - 當存在 Yoga 特定等效插件時,使用了 Envelop 插件 —— 會錯過 HTTP 層級的最佳化(Yoga 回應快取完全跳過解析;Envelop 等效插件無法做到)
- 在解析器中拋出純
Error期望客戶端看到訊息 —— 在生產環境中會被遮罩為 "Unexpected error."
中優先級:
- 未為生產環境設定 CORS 來源 —— 預設為
*,應加以限制 - 在多個伺服器實例間使用記憶體 PubSub —— 事件不會傳播(請使用 Redis 支援的
createRedisEventTarget) - 缺少
graphql對等相依套件 ——graphql-yoga需要graphql作為對等相依套件,請同時安裝兩者 - 呼叫
createSchema但未提供任何 schema —— Yoga 需要一個 schema;它不會推斷出一個
陷阱與邊緣案例:
YogaInitialContext.request是 Fetch API 的Request,而非 Node.js 的IncomingMessage—— 請使用request.headers.get(),而不是req.headers- v5 中的插件執行順序已更改——透過
onPluginInit中的addPlugin新增的插件現在會緊接在新增的插件之後執行,而不是最後 useResponseCache的session回呼必須為 PRIVATE 作用域回傳一個字串(使用者 ID),或為公開作用域回傳null—— 回傳undefined會破壞快取- SSE 訂閱透過 HTTP (text/event-stream) 進行 —— 某些代理可能會緩衝事件;請為 Nginx 設定
X-Accel-Buffering: no - 上傳中的
File標量會提供一個 WHATWGFile物件 —— 請使用.text()、.arrayBuffer()或.stream()方法(而非直接的 Node.jsBuffer) - Yoga 內建的 GraphiQL 預設為啟用 —— 在生產環境中使用
graphiql: false停用 - 將
maskedErrors設定為false會停用 ALL 遮罩,包括堆疊追蹤 —— 請改用自訂maskError函數進行選擇性暴露 - 根據 Fetch 規範,瀏覽器會拒絕使用
credentials: true搭配origin: '*'——請指定準確的來源
</red_flags>
<critical_reminders>
關鍵提醒
所有程式碼必須遵循 CLAUDE.md 中的專案慣例
(你必須從 'graphql' 匯入 GraphQLError,而不是從 'graphql-yoga' —— 這是標準的 graphql-js 匯出)
(你必須優先使用 Yoga 特定插件而非 Envelop 等效插件 —— Yoga 插件在 HTTP 層運作,可以為快取/持久化的結果完全跳過 GraphQL 執行)
(你必須使用 createSchema 從 'graphql-yoga' 進行 schema-first 開發 —— 在 v5 中,不支援將原始的 typeDefs/resolvers 物件直接傳遞給 createYoga)
(你必須為所有數值使用具名常數 —— 逾時、TTL、連接埠號碼、限制)
未能遵循這些規則將會導致導入錯誤或執行階段問題。
請在提示時參閱 reference.md 以獲取完整的決策框架和生產環境檢查清單。
</critical_reminders>