Communitygithub.com

agents-inc/skills

GraphQL Yoga v5 Server, Envelop-Plugins, Subscriptions, Fehlermaskierung

Was ist skills?

Diese Skill bietet ein vollständiges Set an Mustern und Best Practices für den Aufbau eines GraphQL-Servers mit GraphQL Yoga v5. Sie umfasst die serverseitige Konfiguration mit `createYoga` und `createSchema`, die typsichere Kontexterstellung, die Integration des Envelop-Plugin-Systems und dessen Yoga-spezifische Optimierungen. Besondere Schwerpunkte sind Subscriptions via SSE (standardmäßig) oder WebSocket, die Fehlermaskierung zur Absicherung von Produktionsumgebungen sowie die Unterstützung von Dateiuploads. Die Skill richtet sich an Entwickler, die einen flexiblen, Fetch-API-kompatiblen GraphQL-Server auf verschiedenen Laufzeitumgebungen wie Node.js, Bun, Deno oder Cloudflare Workers betreiben möchten.

Funktioniert mit✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/agents-inc/skills/tree/HEAD/src/skills/api-graphql-yoga

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

GraphQL Yoga Patterns

Kurzanleitung: Verwenden Sie createYoga + createSchema für einen Fetch-API-kompatiblen GraphQL-Server, der auf jeder JS-Laufzeitumgebung läuft. Yoga v5 nutzt Envelop für die Plugin-Komposition, SSE für Subscriptions standardmäßig, eine eingebaute Fehlermaskierung und CORS out of the box. Importieren Sie GraphQLError aus graphql (nicht aus graphql-yoga) für beabsichtigte clientseitige Fehler. Bevorzugen Sie Yoga-spezifische Plugins gegenüber Envelop-Äquivalenten für HTTP-Level-Optimierungen.


<critical_requirements>

KRITISCH: Vor der Nutzung dieser Skill

Der gesamte Code muss den Projektkonventionen in CLAUDE.md folgen (kebab-case, benannte Exporte, Importsortierung, import type, benannte Konstanten)

(Sie MÜSSEN GraphQLError aus 'graphql' importieren, NICHT aus 'graphql-yoga' – es ist der Standard-Export von graphql-js)

(Sie MÜSSEN Yoga-spezifische Plugins gegenüber Envelop-Äquivalenten bevorzugen – Yoga-Plugins arbeiten auf der HTTP-Ebene und können die GraphQL-Ausführung für zwischengespeicherte/persistierte Ergebnisse vollständig überspringen)

(Sie MÜSSEN createSchema aus 'graphql-yoga' für schema-first verwenden – das direkte Übergeben von rohen typeDefs/resolvers-Objekten an createYoga wird in v5 nicht unterstützt)

(Sie MÜSSEN benannte Konstanten für alle numerischen Werte verwenden – Timeouts, TTLs, Portnummern, Limits)

</critical_requirements>


Auto-Erkennung: GraphQL Yoga, graphql-yoga, createYoga, createSchema, createPubSub, Envelop, useResponseCache, useCSRFPrevention, usePersistedOperations, GraphQL Subscriptions SSE, Fehlermaskierung, maskedErrors, graphql-ws, Yoga Plugin Hooks, onRequest, onParams

Wann verwenden:

  • Aufbau eines GraphQL-Servers, der auf Node.js, Bun, Deno oder Cloudflare Workers laufen soll
  • APIs, die Subscriptions via SSE (Standard) oder WebSocket benötigen
  • Erweiterung der GraphQL-Ausführung mit Envelop-Plugins (Caching, Authentifizierung, Logging)
  • Dateiuploads mit dem GraphQL Multipart Request Spec
  • Produktions-APIs, die Fehlermaskierung, CORS und CSRF-Schutz benötigen

Wann NICHT verwenden:

  • Nur-REST-APIs ohne GraphQL-Bedarf
  • Einfaches CRUD, bei dem die integrierten Routen-Handler eines Frameworks ausreichen
  • Wenn Sie ein föderiertes Gateway benötigen (erwägen Sie eine dedizierte Gateway-Lösung)

Abgedeckte Schlüsselmuster:

  • Server-Setup mit createYoga und createSchema (schema-first)
  • Typsicherer Kontext mit Generics auf createYoga<ServerContext>
  • Envelop-Plugin-System: Lifecycle-Hooks, benutzerdefinierte Plugins, Yoga-spezifische Plugins
  • Subscriptions: SSE (Standard), WebSocket via graphql-ws, integriertes PubSub
  • Fehlermaskierung und beabsichtigte GraphQLError-Exposition
  • Dateiuploads mit WHATWG File-Skalar
  • Produktionshärtung: CORS, CSRF-Prävention, GraphQL Armor, Logging
  • Cross-Runtime-Bereitstellung: Node.js, Bun, Deno, Cloudflare Workers

Detailierte Ressourcen:


Philosophie

GraphQL Yoga ist ein batteriebetriebener, Fetch-API-kompatibler GraphQL-Server. Sein Kern basiert auf der WHATWG-Fetch-API (Request/Response), was ihn laufzeitunabhängig macht – derselbe Server-Code wird auf Node.js, Bun, Deno und Edge-Laufzeiten bereitgestellt. Das Envelop-Plugin-System bietet zusammensetzbare Middleware sowohl auf der HTTP- als auch auf der GraphQL-Ausführungsebene.

Schema-Ansatz: Yoga ist schema-bibliotheksunabhängig. Verwenden Sie createSchema (schema-first SDL), Pothos (code-first) oder reines graphql-js – alles, was ein GraphQLSchema erzeugt, funktioniert.

Plugin-Priorität: Wenn sowohl ein Envelop-Plugin als auch ein Yoga-spezifisches Plugin für dieselbe Funktion existieren (Caching, persistierte Operationen, defer/stream), wählen Sie immer die Yoga-Variante. Yoga-Plugins haken in die HTTP-Ebene ein und können die Verarbeitung vor der GraphQL-Ausführung unterbrechen, wobei sie das Parsen und Validieren für zwischengespeicherte oder persistierte Ergebnisse vollständig überspringen.

Fehlerphilosophie: Alle unerwarteten Fehler werden standardmäßig in der Produktion maskiert. Beabsichtigte Fehler werden als GraphQLError aus dem graphql-Paket geworfen – diese umgehen die Maskierung und erreichen Clients mit ihrer Nachricht und Erweiterungen intakt.


Kernmuster

Muster 1: Server-Setup mit createYoga

Erstellen Sie eine Yoga-Instanz mit createSchema für SDL-basierte Schemas. Die Yoga-Instanz IST ein Fetch-API-Handler – übergeben Sie sie direkt an den HTTP-Server einer beliebigen Laufzeitumgebung.

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`);
});

Warum gut: createSchema kapselt makeExecutableSchema, die Yoga-Instanz ist ein standardmäßiger Fetch-Handler, funktioniert auf jeder Laufzeitumgebung

Siehe examples/core.md für vollständiges Setup, Cross-Runtime-Bereitstellung und typsicheren Kontext.


Muster 2: Typsicherer Kontext

Übergeben Sie ein Generic an createYoga für die serverseitige Kontexttypisierung. Die context-Factory erhält YogaInitialContext (enthält request und params) und gibt Ihren benutzerdefinierten Kontext zurück.

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 };
  },
});

Warum gut: Generics fließen in den Resolver-Kontext-Parameter, request verwendet die standardmäßige Fetch-API (nicht frameworkspezifisches req/res)

Siehe examples/core.md für vollständige Kontextmuster.


Muster 3: Envelop-Plugin-System

Plugins werden im plugins-Array übergeben. Verwenden Sie Yoga-spezifische Plugins, wenn verfügbar – sie arbeiten auf der HTTP-Ebene und können die GraphQL-Ausführung vollständig überspringen.

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,
    }),
  ],
});

Warum gut: Der Yoga-Antwort-Cache überspringt das Parsen/Validieren für zwischengespeicherte Ergebnisse (das Envelop-Äquivalent kann das nicht), Plugins komponieren ohne Konflikte

Siehe examples/plugins.md für benutzerdefinierte Plugins, Lifecycle-Hooks und alle Yoga-spezifischen Plugins.


Muster 4: Subscriptions mit SSE (Standard)

Yoga verwendet standardmäßig Server-Sent Events für Subscriptions – kein WebSocket-Setup erforderlich. Verwenden Sie die AsyncGenerator-Syntax in Subscription-Resolvern.

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 };
          }
        },
      },
    },
  },
});

Warum gut: keine WebSocket-Infrastruktur erforderlich, funktioniert durch HTTP-Proxies und Load-Balancer, graphql-sse-Bibliothek für Clients

Siehe examples/subscriptions.md für PubSub, WebSocket-Setup und Filterung.


Muster 5: Fehlermaskierung und GraphQLError

Yoga maskiert standardmäßig alle unerwarteten Fehler. Werfen Sie GraphQLError (aus graphql) für beabsichtigte clientseitige Fehler – diese umgehen die Maskierung.

import { GraphQLError } from "graphql";

const NOT_FOUND_CODE = "USER_NOT_FOUND";

throw new GraphQLError("User not found", {
  extensions: { code: NOT_FOUND_CODE },
});

Warum gut: unerwartete Fehler geben niemals Interna preis (Datenbankdetails, Stack-Traces), beabsichtigte Fehler werden mit Nachricht + Erweiterungen durchgelassen

Siehe examples/error-handling.md für benutzerdefinierte Maskierung, Deaktivierung der Maskierung und den Entwicklungsmodus.


Muster 6: Dateiuploads

Yoga unterstützt den GraphQL Multipart Request Spec. Fügen Sie einen File-Skalar hinzu und empfangen Sie WHATWG File-Objekte in Resolvern.

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();
        // Dateiinhalt verarbeiten
        return true;
      },
    },
  },
});

Warum gut: verwendet die standardmäßige WHATWG-File-API (wie im Browser), keine zusätzlichen Pakete erforderlich, deaktivieren mit multipart: false

Siehe examples/core.md für vollständige Dateiupload-Muster.


<decision_framework>

Entscheidungsrahmen

Schema-Ansatz

Auto-generierte Typen aus SDL benötigt?
+-- JA --> createSchema (schema-first mit typeDefs + resolvers)
+-- NEIN  --> Vollständige TypeScript-Inferenz in der Schema-Definition gewünscht?
    +-- JA --> Code-first-Bibliothek (z.B. Pothos) – resultierendes GraphQLSchema an Yoga übergeben
    +-- NEIN  --> Reines graphql-js GraphQLSchema

Subscription Transport

Subscriptions benötigt?
+-- JA --> Benötigen Clients bidirektionale Kommunikation?
|   +-- JA --> WebSocket via graphql-ws (Pakete ws + graphql-ws hinzufügen)
|   +-- NEIN  --> SSE (Standard, null Konfiguration, funktioniert durch Proxies)
+-- NEIN  --> Kein Subscription-Setup erforderlich

Plugin-Auswahl

Funktion als Yoga-spezifisches Plugin verfügbar?
+-- JA --> Yoga-Plugin verwenden (HTTP-Level-Hooks, kann Ausführung überspringen)
+-- NEIN  --> Envelop-Plugin verwenden (GraphQL-Ausführungs-Level-Hooks)

Yoga-spezifische Plugins (Envelop vorziehen)

PluginPaketWarum Yoga-spezifisch
Response Cache@graphql-yoga/plugin-response-cacheÜberspringt Ausführung für gecachte Abfragen
Persisted Operations@graphql-yoga/plugin-persisted-operationsLehnt unbekannte Operationen auf HTTP-Ebene ab
Defer/Stream@graphql-yoga/plugin-defer-streamStreamt via HTTP Chunked Encoding
CSRF Prevention@graphql-yoga/plugin-csrf-preventionErfordert benutzerdefinierten Header vor dem Parsen
GraphQL SSE@graphql-yoga/plugin-graphql-sseEinzelverbindungs-SSE-Modus

</decision_framework>


<red_flags>

ROTE FLAGGEN

Hohe Priorität:

  • Importieren von GraphQLError aus graphql-yoga anstatt aus graphql – falsches Paket, wird fehlschlagen
  • Direktes Übergeben von typeDefs/resolvers-Objekten an createYoga ohne createSchema – wird in v5 nicht unterstützt
  • Verwenden eines Envelop-Plugins, wenn ein Yoga-spezifisches Äquivalent existiert – verpasst HTTP-Level-Optimierungen (der Yoga-Antwort-Cache überspringt das Parsen vollständig; das Envelop-Äquivalent kann das nicht)
  • Werfen eines einfachen Error in Resolvern in der Erwartung, dass Clients die Nachricht sehen – wird in der Produktion zu "Unerwarteter Fehler." maskiert

Mittlere Priorität:

  • Nicht Konfigurieren von CORS-Ursprüngen für die Produktion – Standard ist *, das eingeschränkt werden sollte
  • Verwenden von In-Memory-PubSub über mehrere Serverinstanzen hinweg – Ereignisse werden nicht weitergeleitet (verwenden Sie Redis-gestütztes createRedisEventTarget)
  • Fehlende graphql-Peer-Abhängigkeit – graphql-yoga benötigt graphql als Peer, installieren Sie beide
  • Aufrufen von createSchema ohne Schema überhaupt – Yoga benötigt ein Schema; es leitet keines ab

Tücken & Randfälle:

  • YogaInitialContext.request ist ein Fetch-API-Request, kein Node.js-IncomingMessage – verwenden Sie request.headers.get(), nicht req.headers
  • Die Plugin-Ausführungsreihenfolge hat sich in v5 geändert – Plugins, die über addPlugin in onPluginInit hinzugefügt werden, werden jetzt unmittelbar nach dem hinzufügenden Plugin ausgeführt, nicht als letztes
  • Der session-Rückruf von useResponseCache muss einen String (Benutzer-ID) für den PRIVATEN Bereich oder null für öffentlich zurückgeben – das Zurückgeben von undefined bricht das Caching
  • SSE-Subscriptions gehen durch HTTP (text/event-stream) – einige Proxys puffern Ereignisse; setzen Sie X-Accel-Buffering: no für Nginx
  • Der File-Skalar bei Uploads liefert ein WHATWG-File-Objekt – verwenden Sie die Methoden .text(), .arrayBuffer() oder .stream() (nicht direkt Node.js Buffer)
  • Yogas eingebautes GraphiQL ist standardmäßig aktiviert – deaktivieren Sie es mit graphiql: false in der Produktion
  • maskedErrors auf false gesetzt deaktiviert die gesamte Maskierung einschließlich Stack-Traces – verwenden Sie stattdessen die benutzerdefinierte maskError-Funktion für selektive Exposition
  • CORS credentials: true mit origin: '*' wird von Browsern laut Fetch-Spezifikation abgelehnt – geben Sie exakte Ursprünge an

</red_flags>


<critical_reminders>

KRITISCHE ERINNERUNGEN

Der gesamte Code muss den Projektkonventionen in CLAUDE.md folgen

(Sie MÜSSEN GraphQLError aus 'graphql' importieren, NICHT aus 'graphql-yoga' – es ist der Standard-Export von graphql-js)

(Sie MÜSSEN Yoga-spezifische Plugins gegenüber Envelop-Äquivalenten bevorzugen – Yoga-Plugins arbeiten auf der HTTP-Ebene und können die GraphQL-Ausführung für zwischengespeicherte/persistierte Ergebnisse vollständig überspringen)

(Sie MÜSSEN createSchema aus 'graphql-yoga' für schema-first verwenden – das direkte Übergeben von rohen typeDefs/resolvers-Objekten an createYoga wird in v5 nicht unterstützt)

(Sie MÜSSEN benannte Konstanten für alle numerischen Werte verwenden – Timeouts, TTLs, Portnummern, Limits)

Die Nichtbeachtung dieser Regeln führt zu Importfehlern, Sicherheitslücken oder Laufzeitfehlern.


Nächste Schritte

  1. Sofort lesen → examples/core.md (grundlegendes Server-Setup, Schema, Resolver, Cross-Runtime-Einsatz)
  2. Plugin-Integration → examples/plugins.md (Yoga- und Envelop-Plugins, Lifecycle-Hooks, benutzerdefinierte Plugins)
  3. Subscriptions → examples/subscriptions.md (SSE, WebSocket, PubSub, Filterung)
  4. Fehlerbehandlung → examples/error-handling.md (Maskierung, GraphQLError, benutzerdefinierte Maskierung)
  5. Produktion → examples/production.md (CORS, CSRF, Caching, Persistierte Operationen, Logging)
  6. Referenz → reference.md (Entscheidungsrahmen, Plugin-Referenz, Produktions-Checkliste)

</critical_reminders>


Wenn Sie unsicher sind, welches Muster Sie verwenden sollen, lesen Sie die Beispiele und Referenzen. Die Muster in diesem Dokument bauen aufeinander auf, wobei spätere Beispiele Kenntnisse aus früheren voraussetzen.

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Verwandte Skills