Communitygithub.com

agents-inc/skills

Servidor GraphQL Yoga v5, plugins Envelop, suscripciones, enmascaramiento de errores

¿Qué es skills?

Esta skill proporciona una guía completa para construir servidores GraphQL con GraphQL Yoga v5, un servidor GraphQL compatible con la API Fetch y agnóstico al runtime. Cubre desde la configuración básica con `createYoga` y `createSchema` hasta patrones avanzados como suscripciones Server-Sent Events (SSE), enmascaramiento de errores, carga de archivos y plugins Envelop. La skill enfatiza la preferencia por plugins específicos de Yoga sobre los equivalentes de Envelop, ya que operan en la capa HTTP y pueden omitir la ejecución de GraphQL para resultados cacheados o persistidos. También incluye marcos de decisión para seleccionar el enfoque de esquema correcto, transporte de suscripciones y plugins, así como banderas rojas críticas y recordatorios para evitar errores comunes, como importar `GraphQLError` del paquete incorrecto o pasar `typeDefs` y `resolvers` directamente a `createYoga`. Es compatible con Node.js, Bun, Deno y Cloudflare Workers, y se basa en la documentación detallada en archivos de ejemplos y referencia.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de GraphQL Yoga

Guía rápida: Usa createYoga + createSchema para un servidor GraphQL compatible con la API Fetch que funciona en cualquier runtime de JS. Yoga v5 usa Envelop para la composición de plugins, SSE para suscripciones por defecto, enmascaramiento de errores integrado y CORS listo para usar. Importa GraphQLError desde graphql (no graphql-yoga) para errores intencionales visibles al cliente. Prefiere plugins específicos de Yoga sobre los equivalentes de Envelop para optimizaciones a nivel HTTP.


<critical_requirements>

CRÍTICO: Antes de Usar Esta Skill

Todo el código debe seguir las convenciones del proyecto en CLAUDE.md (kebab-case, exportaciones nombradas, orden de importaciones, import type, constantes nombradas)

(DEBES importar GraphQLError desde 'graphql', NO desde 'graphql-yoga' -- es la exportación estándar de graphql-js)

(DEBES preferir plugins específicos de Yoga sobre equivalentes de Envelop -- los plugins de Yoga operan en la capa HTTP y pueden saltar la ejecución completa de GraphQL para resultados cacheados/persistidos)

(DEBES usar createSchema desde 'graphql-yoga' para esquema primero -- pasar objetos typeDefs/resolvers directamente a createYoga no es compatible en v5)

(DEBES usar constantes nombradas para todos los valores numéricos -- timeouts, TTLs, números de puerto, límites)

</critical_requirements>


Auto-detección: GraphQL Yoga, graphql-yoga, createYoga, createSchema, createPubSub, Envelop, useResponseCache, useCSRFPrevention, usePersistedOperations, suscripciones GraphQL SSE, enmascaramiento de errores, maskedErrors, graphql-ws, hooks de plugins Yoga, onRequest, onParams

Cuándo usarlo:

  • Construir un servidor GraphQL que necesite ejecutarse en Node.js, Bun, Deno o Cloudflare Workers
  • APIs que requieran suscripciones mediante SSE (por defecto) o WebSocket
  • Extender la ejecución de GraphQL con plugins Envelop (caché, autenticación, registro)
  • Carga de archivos usando la especificación de Solicitud Multiparte de GraphQL
  • APIs de producción que necesiten enmascaramiento de errores, CORS y protección CSRF

Cuándo NO usarlo:

  • APIs solo REST sin necesidades de GraphQL
  • CRUD simple donde los manejadores de ruta integrados de un framework son suficientes
  • Cuando necesites un gateway federado (considera una solución de gateway dedicada)

Patrones clave cubiertos:

  • Configuración del servidor con createYoga y createSchema (esquema primero)
  • Contexto con seguridad de tipos usando genéricos en createYoga<ServerContext>
  • Sistema de plugins Envelop: hooks de ciclo de vida, plugins personalizados, plugins específicos de Yoga
  • Suscripciones: SSE (por defecto), WebSocket mediante graphql-ws, PubSub integrado
  • Enmascaramiento de errores y exposición intencional de GraphQLError
  • Carga de archivos con el escalar File de WHATWG
  • Fortalecimiento de producción: CORS, prevención CSRF, GraphQL Armor, registro
  • Despliegue en múltiples runtimes: Node.js, Bun, Deno, Cloudflare Workers

Recursos detallados:


Filosofía

GraphQL Yoga es un servidor GraphQL con pilas incluidas y compatible con la API Fetch. Su núcleo está construido sobre la API Fetch de WHATWG (Request/Response), lo que lo hace agnóstico al runtime -- el mismo código de servidor se despliega en Node.js, Bun, Deno y runtimes periféricos. El sistema de plugins Envelop proporciona middleware componible tanto en la capa HTTP como en la de ejecución de GraphQL.

Enfoque de esquema: Yoga es agnóstico a la biblioteca de esquemas. Usa createSchema (SDL primero), Pothos (código primero) o graphql-js vainilla -- cualquier cosa que produzca un GraphQLSchema funciona.

Prioridad de plugins: Cuando existan tanto un plugin Envelop como un plugin específico de Yoga para la misma característica (caché, operaciones persistidas, defer/stream), elige siempre la variante de Yoga. Los plugins de Yoga se enganchan en la capa HTTP y pueden cortocircuitar antes de que comience la ejecución de GraphQL, omitiendo el análisis y la validación por completo para resultados cacheados o persistidos.

Filosofía de errores: Todos los errores inesperados se enmascaran por defecto en producción. Los errores intencionales se lanzan como GraphQLError del paquete graphql -- estos evitan el enmascaramiento y llegan a los clientes con su mensaje y extensiones intactos.


Patrones Principales

Patrón 1: Configuración del Servidor con createYoga

Crea una instancia de Yoga con createSchema para esquemas basados en SDL. La instancia de yoga ES un manejador de la API Fetch -- pásalo directamente al servidor HTTP de cualquier 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 }) => `¡Hola, ${name}!`,
      },
    },
  }),
});

const server = createServer(yoga);
server.listen(PORT, () => {
  console.info(`Servidor corriendo en http://localhost:${PORT}/graphql`);
});

Por qué es bueno: createSchema envuelve makeExecutableSchema, la instancia de yoga es un manejador Fetch estándar, funciona en cualquier runtime

Ver examples/core.md para configuración completa, despliegue en múltiples runtimes y contexto con seguridad de tipos.


Patrón 2: Contexto con Seguridad de Tipos

Pasa un genérico a createYoga para tipificar el contexto específico del servidor. La fábrica de context recibe YogaInitialContext (que contiene request y params) y devuelve tu contexto personalizado.

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

Por qué es bueno: los tipos genéricos fluyen al parámetro de contexto del resolutor, request usa la API Fetch estándar (no req/res específicos del framework)

Ver examples/core.md para patrones de contexto completos.


Patrón 3: Sistema de Plugins Envelop

Los plugins se pasan en el array plugins. Usa plugins específicos de Yoga cuando estén disponibles -- operan en la capa HTTP y pueden saltar la ejecución completa de 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,
    }),
  ],
});

Por qué es bueno: la caché de respuestas de Yoga omite el análisis/validación para resultados cacheados (el equivalente de Envelop no puede), los plugins se componen sin conflictos

Ver examples/plugins.md para plugins personalizados, hooks de ciclo de vida y todos los plugins específicos de Yoga.


Patrón 4: Suscripciones con SSE (Por Defecto)

Yoga usa Server-Sent Events por defecto para suscripciones -- no se necesita configuración de WebSocket. Usa la sintaxis AsyncGenerator en los resolutores de suscripción.

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

Por qué es bueno: no se necesita infraestructura WebSocket, funciona a través de proxies HTTP y balanceadores de carga, biblioteca graphql-sse para clientes

Ver examples/subscriptions.md para PubSub, configuración WebSocket y filtrado.


Patrón 5: Enmascaramiento de Errores y GraphQLError

Yoga enmascara todos los errores inesperados por defecto. Lanza GraphQLError (desde graphql) para errores intencionales visibles al cliente -- estos evitan el enmascaramiento.

import { GraphQLError } from "graphql";

const NOT_FOUND_CODE = "USER_NOT_FOUND";

throw new GraphQLError("Usuario no encontrado", {
  extensions: { code: NOT_FOUND_CODE },
});

Por qué es bueno: los errores inesperados nunca filtran detalles internos (detalles de base de datos, trazas de pila), los errores intencionales pasan con mensaje + extensiones

Ver examples/error-handling.md para enmascaramiento personalizado, deshabilitar enmascaramiento y modo de desarrollo.


Patrón 6: Carga de Archivos

Yoga es compatible con la especificación de Solicitud Multiparte de GraphQL. Agrega un escalar File y recibe objetos File de WHATWG en los resolutores.

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();
        // Procesar contenido del archivo
        return true;
      },
    },
  },
});

Por qué es bueno: usa la API File estándar de WHATWG (igual que el navegador), no se necesitan paquetes adicionales, deshabilita con multipart: false

Ver examples/core.md para patrones completos de carga de archivos.


<decision_framework>

Marco de Decisión

Enfoque de Esquema

¿Necesitas tipos generados automáticamente desde SDL?
+-- SÍ --> createSchema (esquema primero con typeDefs + resolvers)
+-- NO  --> ¿Quieres inferencia completa de TypeScript en la definición del esquema?
    +-- SÍ --> Biblioteca código primero (ej. Pothos) -- pasa el GraphQLSchema resultante a Yoga
    +-- NO  --> GraphQLSchema de graphql-js vainilla

Transporte de Suscripciones

¿Necesitas suscripciones?
+-- SÍ --> ¿Los clientes necesitan comunicación bidireccional?
|   +-- SÍ --> WebSocket mediante graphql-ws (agrega paquetes ws + graphql-ws)
|   +-- NO  --> SSE (por defecto, configuración cero, funciona a través de proxies)
+-- NO  --> No se necesita configuración de suscripción

Selección de Plugins

¿La característica está disponible como plugin específico de Yoga?
+-- SÍ --> Usa el plugin de Yoga (hooks a nivel HTTP, puede saltar la ejecución)
+-- NO  --> Usa el plugin Envelop (hooks a nivel de ejecución de GraphQL)

Plugins Específicos de Yoga (Preferir Sobre Envelop)

PluginPaquetePor qué es específico de Yoga
Caché de Respuestas@graphql-yoga/plugin-response-cacheOmite la ejecución para consultas cacheadas
Operaciones Persistidas@graphql-yoga/plugin-persisted-operationsRechaza operaciones desconocidas en la capa HTTP
Defer/Stream@graphql-yoga/plugin-defer-streamTransmite mediante codificación fragmentada HTTP
Prevención CSRF@graphql-yoga/plugin-csrf-preventionRequiere encabezado personalizado antes de analizar
GraphQL SSE@graphql-yoga/plugin-graphql-sseModo SSE de conexión única

</decision_framework>


<red_flags>

SEÑALES ROJAS

Alta Prioridad:

  • Importar GraphQLError desde graphql-yoga en lugar de graphql -- paquete incorrecto, fallará
  • Pasar objetos typeDefs/resolvers directamente a createYoga sin createSchema -- no compatible en v5
  • Usar un plugin Envelop cuando exista un equivalente específico de Yoga -- se pierden las optimizaciones a nivel HTTP (la caché de respuestas de Yoga omite el análisis por completo; el equivalente de Envelop no puede)
  • Lanzar un Error simple en los resolutores esperando que los clientes vean el mensaje -- se enmascara como "Error inesperado." en producción

Prioridad Media:

  • No configurar los orígenes CORS para producción -- el valor predeterminado es *, que debe restringirse
  • Usar PubSub en memoria en múltiples instancias del servidor -- los eventos no se propagarán (usa createRedisEventTarget respaldado por Redis)
  • Falta la dependencia par graphql -- graphql-yoga requiere graphql como par, instala ambos
  • Llamar a createSchema sin ningún esquema -- Yoga requiere un esquema; no lo infiere

Casos Especiales y Trampas:

  • YogaInitialContext.request es una Request de la API Fetch, no un IncomingMessage de Node.js -- usa request.headers.get(), no req.headers
  • El orden de ejecución de los plugins cambió en v5 -- los plugins agregados mediante addPlugin en onPluginInit ahora se ejecutan inmediatamente después del plugin que los agrega, no al final
  • El callback session de useResponseCache debe devolver un string (ID de usuario) para ámbito PRIVADO o null para público -- devolver undefined rompe la caché
  • Las suscripciones SSE pasan por HTTP (text/event-stream) -- algunos proxies pueden almacenar eventos en búfer; establece X-Accel-Buffering: no para Nginx
  • El escalar File en las cargas te da un objeto File de WHATWG -- usa los métodos .text(), .arrayBuffer() o .stream() (no Buffer de Node.js directamente)
  • El GraphiQL integrado de Yoga está habilitado por defecto -- deshabilítalo con graphiql: false en producción
  • maskedErrors establecido en false deshabilita TODO el enmascaramiento, incluidas las trazas de pila -- usa la función personalizada maskError en su lugar para exposición selectiva
  • CORS credentials: true con origin: '*' es rechazado por los navegadores según la especificación Fetch -- especifica orígenes exactos

</red_flags>


<critical_reminders>

RECORDATORIOS CRÍTICOS

Todo el código debe seguir las convenciones del proyecto en CLAUDE.md

(DEBES importar GraphQLError desde 'graphql', NO desde 'graphql-yoga' -- es la exportación estándar de graphql-js)

(DEBES preferir plugins específicos de Yoga sobre equivalentes de Envelop -- los plugins de Yoga operan en la capa HTTP y pueden saltar la ejecución completa de GraphQL para resultados cacheados/persistidos)

(DEBES usar createSchema desde 'graphql-yoga' para esquema primero -- pasar objetos typeDefs/resolvers directamente a createYoga no es compatible en v5)

(DEBES usar constantes nombradas para todos los valores numéricos -- timeouts, TTLs, números de puerto, límites)

No seguir estas reglas causará errores de importación, problemas de enmascaramiento de errores, degradación del rendimiento o violaciones de seguridad.

</critical_reminders>

Individual skills in this repo

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

Skills relacionados