Communitygithub.com

agents-inc/skills

Serveur GraphQL Yoga v5, plugins Envelop, souscriptions, masquage d'erreurs

Qu'est-ce que skills ?

Cette compétence fournit un guide complet pour configurer un serveur GraphQL avec GraphQL Yoga v5, un serveur compatible Fetch API fonctionnant sur n'importe quel runtime JavaScript (Node.js, Bun, Deno, Cloudflare Workers). Elle couvre l'utilisation de `createYoga` et `createSchema` pour les schémas SDL, le système de plugins Envelop pour la composition de middleware, les souscriptions via SSE (par défaut) ou WebSocket, le masquage des erreurs, et les téléchargements de fichiers. La compétence insiste sur des pratiques critiques : importer `GraphQLError` depuis `'graphql'` et non `'graphql-yoga'`, privilégier les plugins Yoga aux équivalents Envelop (optimisations au niveau HTTP), et utiliser `createSchema` au lieu de passer `typeDefs`/`resolvers` directement à `createYoga`. Un cadre de décision aide à choisir l'approche de schéma, le transport de souscription et la sélection de plugins, tandis qu'une liste de drapeaux rouges met en garde contre les erreurs courantes comme l'utilisation de plugins Envelop alors qu'un plugin Yoga spécifique existe ou le lancer d'erreurs non GraphQL.

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles GraphQL Yoga

Guide rapide : Utilisez createYoga + createSchema pour un serveur GraphQL compatible Fetch API fonctionnant sur n'importe quel runtime JS. Yoga v5 utilise Envelop pour la composition de plugins, SSE pour les souscriptions par défaut, le masquage intégré des erreurs et CORS prêt à l'emploi. Importez GraphQLError depuis graphql (pas graphql-yoga) pour les erreurs intentionnelles côté client. Préférez les plugins spécifiques à Yoga aux équivalents Envelop pour les optimisations au niveau HTTP.


<exigences_critiques>

CRITIQUE : Avant d'Utiliser Cette Compétence

Tout code doit respecter les conventions du projet dans CLAUDE.md (kebab-case, exports nommés, ordre des imports, import type, constantes nommées)

(Vous DEVEZ importer GraphQLError depuis 'graphql', PAS depuis 'graphql-yoga' — c'est l'export standard de graphql-js)

(Vous DEVEZ préférer les plugins spécifiques à Yoga aux équivalents Envelop — les plugins Yoga opèrent au niveau HTTP et peuvent ignorer totalement l'exécution GraphQL pour les résultats mis en cache/ persistés)

(Vous DEVEZ utiliser createSchema depuis 'graphql-yoga' pour les schémas SDL — passer des objets typeDefs/resolvers bruts directement à createYoga n'est pas supporté dans v5)

(Vous DEVEZ utiliser des constantes nommées pour toutes les valeurs numériques — timeouts, TTL, numéros de port, limites)

</exigences_critiques>


Auto-détection : GraphQL Yoga, graphql-yoga, createYoga, createSchema, createPubSub, Envelop, useResponseCache, useCSRFPrevention, usePersistedOperations, souscriptions GraphQL SSE, masquage d'erreurs, maskedErrors, graphql-ws, hooks de plugin Yoga, onRequest, onParams

Quand utiliser :

  • Construire un serveur GraphQL devant fonctionner sur Node.js, Bun, Deno ou Cloudflare Workers
  • API nécessitant des souscriptions via SSE (par défaut) ou WebSocket
  • Étendre l'exécution GraphQL avec des plugins Envelop (mise en cache, authentification, journalisation)
  • Téléchargements de fichiers utilisant la spécification GraphQL Multipart Request
  • API de production nécessitant le masquage d'erreurs, CORS et la protection CSRF

Quand NE PAS utiliser :

  • API REST uniquement sans besoins GraphQL
  • CRUD simple où les gestionnaires de route intégrés d'un framework suffisent
  • Lorsque vous avez besoin d'une passerelle fédérée (considérez une solution de passerelle dédiée)

Modèles clés couverts :

  • Configuration du serveur avec createYoga et createSchema (schéma d'abord)
  • Contexte typé avec génériques sur createYoga<ServerContext>
  • Système de plugins Envelop : hooks de cycle de vie, plugins personnalisés, plugins spécifiques à Yoga
  • Souscriptions : SSE (par défaut), WebSocket via graphql-ws, PubSub intégré
  • Masquage d'erreurs et exposition intentionnelle de GraphQLError
  • Téléchargements de fichiers avec le scalaire File WHATWG
  • Durcissement de production : CORS, prévention CSRF, GraphQL Armor, journalisation
  • Déploiement multi-runtime : Node.js, Bun, Deno, Cloudflare Workers

Ressources détaillées :


Philosophie

GraphQL Yoga est un serveur GraphQL clé en main, compatible Fetch API. Son cœur est construit sur l'API WHATWG Fetch (Request/Response), ce qui le rend indépendant du runtime — le même code serveur se déploie sur Node.js, Bun, Deno et les runtimes edge. Le système de plugins Envelop fournit un middleware composable aux niveaux HTTP et d'exécution GraphQL.

Approche du schéma : Yoga est indépendant de la bibliothèque de schéma. Utilisez createSchema (SDL d'abord), Pothos (code-first) ou vanilla graphql-js — tout ce qui produit un GraphQLSchema fonctionne.

Priorité des plugins : Lorsqu'un plugin Envelop et un plugin spécifique à Yoga existent pour la même fonctionnalité (mise en cache, opérations persistées, defer/stream), choisissez toujours la variante Yoga. Les plugins Yoga se branchent sur la couche HTTP et peuvent court-circuiter avant le début de l'exécution GraphQL, ignorant ainsi l'analyse et la validation pour les résultats en cache ou persistés.

Philosophie des erreurs : Toutes les erreurs inattendues sont masquées par défaut en production. Les erreurs intentionnelles sont levées en tant que GraphQLError du package graphql — elles contournent le masquage et atteignent les clients avec leur message et leurs extensions intactes.


Modèles principaux

Modèle 1 : Configuration du Serveur avec createYoga

Créez une instance Yoga avec createSchema pour les schémas basés sur SDL. L'instance yoga EST un gestionnaire d'API Fetch — passez-la directement au serveur HTTP de n'importe quel runtime.

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

Pourquoi c'est bon : createSchema encapsule makeExecutableSchema, l'instance yoga est un gestionnaire Fetch standard, fonctionne sur n'importe quel runtime

Voir examples/core.md pour une configuration complète, un déploiement multi-runtime et un contexte typé.


Modèle 2 : Contexte Typé

Passez un générique à createYoga pour le typage du contexte spécifique au serveur. La fabrique context reçoit YogaInitialContext (contenant request et params) et retourne votre contexte personnalisé.

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

Pourquoi c'est bon : les types génériques circulent vers le paramètre de contexte du résolveur, request utilise l'API Fetch standard (pas req/res spécifique au framework)

Voir examples/core.md pour les modèles de contexte complets.


Modèle 3 : Système de Plugins Envelop

Les plugins sont passés dans le tableau plugins. Utilisez les plugins spécifiques à Yoga lorsqu'ils sont disponibles — ils opèrent au niveau HTTP et peuvent ignorer totalement l'exécution 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,
    }),
  ],
});

Pourquoi c'est bon : le cache de réponse Yoga ignore l'analyse/validation pour les résultats mis en cache (l'équivalent Envelop ne le peut pas), les plugins se composent sans conflits

Voir examples/plugins.md pour les plugins personnalisés, les hooks de cycle de vie et tous les plugins spécifiques à Yoga.


Modèle 4 : Souscriptions avec SSE (Par Défaut)

Yoga utilise les Server-Sent Events par défaut pour les souscriptions — aucune configuration WebSocket nécessaire. Utilisez la syntaxe AsyncGenerator dans les résolveurs de souscription.

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

Pourquoi c'est bon : aucune infrastructure WebSocket nécessaire, fonctionne via les proxys HTTP et les équilibreurs de charge, bibliothèque graphql-sse pour les clients

Voir examples/subscriptions.md pour PubSub, configuration WebSocket et filtrage.


Modèle 5 : Masquage d'Erreurs et GraphQLError

Yoga masque toutes les erreurs inattendues par défaut. Lancez GraphQLError (depuis graphql) pour les erreurs intentionnelles côté client — elles contournent le masquage.

import { GraphQLError } from "graphql";

const NOT_FOUND_CODE = "USER_NOT_FOUND";

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

Pourquoi c'est bon : les erreurs inattendues ne divulguent jamais les détails internes (détails de base de données, traces de pile), les erreurs intentionnelles passent avec le message + les extensions

Voir examples/error-handling.md pour le masquage personnalisé, la désactivation du masquage et le mode développement.


Modèle 6 : Téléchargements de Fichiers

Yoga supporte la spécification GraphQL Multipart Request. Ajoutez un scalaire File et recevez des objets File WHATWG dans les résolveurs.

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();
        // Traiter le contenu du fichier
        return true;
      },
    },
  },
});

Pourquoi c'est bon : utilise l'API WHATWG File standard (identique au navigateur), aucun package supplémentaire nécessaire, désactivable avec multipart: false

Voir examples/core.md pour les modèles de téléchargement de fichiers complets.


<cadre_decision>

Cadre de Décision

Approche du Schéma

Besoin de types auto-générés à partir de SDL ?
+-- OUI --> createSchema (schéma d'abord avec typeDefs + resolvers)
+-- NON  --> Souhaitez-vous une inférence TypeScript complète dans la définition du schéma ?
    +-- OUI --> Bibliothèque code-first (ex. Pothos) — passez le GraphQLSchema résultant à Yoga
    +-- NON  --> GraphQLSchema vanilla graphql-js

Transport de Souscription

Besoin de souscriptions ?
+-- OUI --> Les clients ont-ils besoin de communication bidirectionnelle ?
|   +-- OUI --> WebSocket via graphql-ws (ajoutez les packages ws + graphql-ws)
|   +-- NON  --> SSE (par défaut, zéro configuration, fonctionne via les proxys)
+-- NON  --> Aucune configuration de souscription nécessaire

Sélection de Plugin

Fonctionnalité disponible en tant que plugin spécifique à Yoga ?
+-- OUI --> Utilisez le plugin Yoga (hooks au niveau HTTP, peut ignorer l'exécution)
+-- NON  --> Utilisez le plugin Envelop (hooks au niveau de l'exécution GraphQL)

Plugins Spécifiques à Yoga (Préférez aux Envelop)

PluginPackagePourquoi Spécifique à Yoga
Cache de Réponse@graphql-yoga/plugin-response-cacheIgnore l'exécution pour les requêtes en cache
Opérations Persistées@graphql-yoga/plugin-persisted-operationsRejette les opérations inconnues au niveau HTTP
Defer/Stream@graphql-yoga/plugin-defer-streamStreame via l'encodage par morceaux HTTP
Prévention CSRF@graphql-yoga/plugin-csrf-preventionNécessite un en-tête personnalisé avant l'analyse
GraphQL SSE@graphql-yoga/plugin-graphql-sseMode SSE à connexion unique

</cadre_decision>


<drapeaux_rouges>

DRAPEAUX ROUGES

Haute Priorité :

  • Importer GraphQLError depuis graphql-yoga au lieu de graphql — mauvais package, échouera
  • Passer des objets typeDefs/resolvers directement à createYoga sans createSchema — non supporté dans v5
  • Utiliser un plugin Envelop alors qu'un équivalent spécifique à Yoga existe — manque les optimisations au niveau HTTP (le cache de réponse Yoga ignore totalement l'analyse ; l'équivalent Envelop ne le peut pas)
  • Lancer une Error simple dans les résolveurs en s'attendant à ce que les clients voient le message — masqué en "Erreur inattendue." en production

Priorité Moyenne :

  • Ne pas configurer les origines CORS pour la production — la valeur par défaut est *, qui doit être restreinte
  • Utiliser PubSub en mémoire sur plusieurs instances de serveur — les événements ne se propageront pas (utilisez createRedisEventTarget basé sur Redis)
  • Dépendance graphql manquante — graphql-yoga nécessite graphql comme dépendance, installez les deux
  • Appeler createSchema sans schéma du tout — Yoga nécessite un schéma ; il n'en infère pas

Pièges et Cas Limites :

  • YogaInitialContext.request est une Request de l'API Fetch, pas un IncomingMessage Node.js — utilisez request.headers.get(), pas req.headers
  • L'ordre d'exécution des plugins a changé dans v5 — les plugins ajoutés via addPlugin dans onPluginInit s'exécutent maintenant immédiatement après le plugin ajouteur, pas en dernier
  • Le callback session de useResponseCache doit retourner une chaîne (ID utilisateur) pour la portée PRIVÉE ou null pour publique — retourner undefined casse la mise en cache
  • Les souscriptions SSE passent par HTTP (text/event-stream) — certains proxys peuvent bufferiser les événements ; définissez X-Accel-Buffering: no pour Nginx
  • Le scalaire File dans les téléchargements vous donne un objet WHATWG File — utilisez les méthodes .text(), .arrayBuffer() ou .stream() (pas Buffer Node.js directement)
  • Le GraphiQL intégré de Yoga est activé par défaut — désactivez avec graphiql: false en production
  • maskedErrors défini sur false désactive TOUT le masquage, y compris les traces de pile — utilisez plutôt la fonction personnalisée maskError pour une exposition sélective
  • credentials: true de CORS avec origin: '*' est rejeté par les navigateurs selon la spécification Fetch — spécifiez des origines exactes

</drapeaux_rouges>


<rappels_critiques>

RAPPELS CRITIQUES

Tout code doit respecter les conventions du projet dans CLAUDE.md

(Vous DEVEZ importer GraphQLError depuis 'graphql', PAS depuis 'graphql-yoga' — c'est l'export standard de graphql-js)

(Vous DEVEZ préférer les plugins spécifiques à Yoga aux équivalents Envelop — les plugins Yoga opèrent au niveau HTTP et peuvent ignorer totalement l'exécution GraphQL pour les résultats mis en cache/persistés)

(Vous DEVEZ utiliser createSchema depuis 'graphql-yoga' pour les schémas SDL — passer des objets typeDefs/resolvers bruts directement à createYoga n'est pas supporté dans v5)

(Vous DEVEZ utiliser des constantes nommées pour toutes les valeurs numériques — timeouts, TTL, numéros de port, limites)

Le non-respect de ces règles entraînera des échecs d'importation, des résultats inattendus ou des vulnérabilités de sécurité.

</rappels_critiques>


Récupération

Problèmes Courants

SymptômeCauseSolution
GraphQLError is not a constructorImporté depuis graphql-yoga au lieu de graphqlRemplacez l'import par import { GraphQLError } from "graphql"
Toutes les erreurs apparaissent comme "Erreur inattendue."GraphQLError importé depuis le mauvais package OU maskedErrors est activé et vous lancez ErrorVérifiez l'import de GraphQLError, utilisez GraphQLError pour les erreurs intentionnelles
Les résolveurs ne reçoivent pas les types de contexteLe générique de createYoga est manquant ou ne correspond pasAjoutez un générique : createYoga<ServerContext>, vérifiez qu'il correspond à l'interface
Les souscriptions SSE ne fonctionnent pas derrière un proxyLe proxy bufferise le flux d'événementsAjoutez l'en-tête X-Accel-Buffering: no (Nginx) ou Cache-Control: no-cache
createYoga se plaint de typeDefs inconnuDans v5, typeDefs doit être passé dans createSchemaEnveloppez avec createSchema({ typeDefs, resolvers })

Voir reference.md pour un dépannage complet.

Individual skills in this repo

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

Skills associés