agentsclimarketplace

Api graphql yoga

Skill agents-inc/skills/src/skills/api-graphql-yoga

GraphQL Yoga v5 server, Envelop plugins, subscriptions, error maskingFrom its SKILL.md

Install
npx -y skills add agents-inc/skills --skill api-graphql-yoga

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 20 stars20 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.9 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it

GraphQL Yoga Patterns

Quick Guide: Use createYoga + createSchema for a Fetch API-compatible GraphQL server that runs on any JS runtime. Yoga v5 uses Envelop for plugin composition, SSE for subscriptions by default, built-in error masking, and CORS out of the box. Import GraphQLError from graphql (not graphql-yoga) for intentional client-facing errors. Prefer Yoga-specific plugins over Envelop equivalents for HTTP-level optimizations.


<critical_requirements>

CRITICAL: Before Using This Skill

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST import GraphQLError from 'graphql', NOT from 'graphql-yoga' -- it is the standard graphql-js export)

(You MUST prefer Yoga-specific plugins over Envelop equivalents -- Yoga plugins operate at the HTTP layer and can skip GraphQL execution entirely for cached/persisted results)

(You MUST use createSchema from 'graphql-yoga' for schema-first -- passing raw typeDefs/resolvers objects directly to createYoga is not supported in v5)

(You MUST use named constants for all numeric values -- timeouts, TTLs, port numbers, limits)

</critical_requirements>


Auto-detection: GraphQL Yoga, graphql-yoga, createYoga, createSchema, createPubSub, Envelop, useResponseCache, useCSRFPrevention, usePersistedOperations, GraphQL subscriptions SSE, error masking, maskedErrors, graphql-ws, Yoga plugin hooks, onRequest, onParams

When to use:

  • Building a GraphQL server that needs to run on Node.js, Bun, Deno, or Cloudflare Workers
  • APIs requiring subscriptions via SSE (default) or WebSocket
  • Extending GraphQL execution with Envelop plugins (caching, auth, logging)
  • File uploads using the GraphQL Multipart Request spec
  • Production APIs needing error masking, CORS, and CSRF protection

When NOT to use:

  • REST-only APIs without GraphQL needs
  • Simple CRUD where a framework's built-in route handlers suffice
  • When you need a federated gateway (consider a dedicated gateway solution)

Key patterns covered:

  • Server setup with createYoga and createSchema (schema-first)
  • Type-safe context with generics on createYoga<ServerContext>
  • Envelop plugin system: lifecycle hooks, custom plugins, Yoga-specific plugins
  • Subscriptions: SSE (default), WebSocket via graphql-ws, built-in PubSub
  • Error masking and intentional GraphQLError exposure
  • File uploads with WHATWG File scalar
  • Production hardening: CORS, CSRF prevention, GraphQL Armor, logging
  • Cross-runtime deployment: Node.js, Bun, Deno, Cloudflare Workers

Detailed Resources:


<philosophy>

Philosophy

GraphQL Yoga is a batteries-included, Fetch API-compatible GraphQL server. Its core is built on the WHATWG Fetch API (Request/Response), making it runtime-agnostic -- the same server code deploys to Node.js, Bun, Deno, and edge runtimes. The Envelop plugin system provides composable middleware at both the HTTP and GraphQL execution layers.

Schema approach: Yoga is schema-library agnostic. Use createSchema (schema-first SDL), Pothos (code-first), or vanilla graphql-js -- anything that produces a GraphQLSchema works.

Plugin priority: When both an Envelop plugin and a Yoga-specific plugin exist for the same feature (caching, persisted operations, defer/stream), always choose the Yoga variant. Yoga plugins hook into the HTTP layer and can short-circuit before GraphQL execution begins, skipping parsing and validation entirely for cached or persisted results.

Error philosophy: All unexpected errors are masked by default in production. Intentional errors are thrown as GraphQLError from the graphql package -- these bypass masking and reach clients with their message and extensions intact.

</philosophy>
<patterns>

Core Patterns

Pattern 1: Server Setup with createYoga

Create a Yoga instance with createSchema for SDL-based schemas. The yoga instance IS a Fetch API handler -- pass it directly to any runtime's HTTP server.

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

Why good: createSchema wraps makeExecutableSchema, yoga instance is a standard Fetch handler, works on any runtime

See examples/core.md for complete setup, cross-runtime deployment, and type-safe context.


Pattern 2: Type-Safe Context

Pass a generic to createYoga for server-specific context typing. The context factory receives YogaInitialContext (containing request and params) and returns your custom 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 };
  },
});

Why good: generic types flow to resolver context parameter, request uses standard Fetch API (not framework-specific req/res)

See examples/core.md for full context patterns.


Pattern 3: Envelop Plugin System

Plugins are passed in the plugins array. Use Yoga-specific plugins when available -- they operate at the HTTP layer and can skip GraphQL execution entirely.

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

Why good: Yoga response cache skips parsing/validation for cached results (Envelop equivalent cannot), plugins compose without conflicts

See examples/plugins.md for custom plugins, lifecycle hooks, and all Yoga-specific plugins.


Pattern 4: Subscriptions with SSE (Default)

Yoga uses Server-Sent Events by default for subscriptions -- no WebSocket setup needed. Use AsyncGenerator syntax in subscription resolvers.

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

Why good: no WebSocket infrastructure needed, works through HTTP proxies and load balancers, graphql-sse library for clients

See examples/subscriptions.md for PubSub, WebSocket setup, and filtering.


Pattern 5: Error Masking and GraphQLError

Yoga masks all unexpected errors by default. Throw GraphQLError (from graphql) for intentional client-facing errors -- these bypass masking.

import { GraphQLError } from "graphql";

const NOT_FOUND_CODE = "USER_NOT_FOUND";

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

Why good: unexpected errors never leak internals (database details, stack traces), intentional errors pass through with message + extensions

See examples/error-handling.md for custom masking, disabling masking, and development mode.


Pattern 6: File Uploads

Yoga supports the GraphQL Multipart Request spec. Add a File scalar and receive WHATWG File objects in resolvers.

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

Why good: uses standard WHATWG File API (same as browser), no extra packages needed, disable with multipart: false

See examples/core.md for complete file upload patterns.

</patterns>

<decision_framework>

Decision Framework

Schema Approach

Need auto-generated types from SDL?
+-- YES --> createSchema (schema-first with typeDefs + resolvers)
+-- NO  --> Want full TypeScript inference in schema definition?
    +-- YES --> Code-first library (e.g. Pothos) -- pass resulting GraphQLSchema to Yoga
    +-- NO  --> Vanilla graphql-js GraphQLSchema

Subscription Transport

Need subscriptions?
+-- YES --> Do clients need bidirectional communication?
|   +-- YES --> WebSocket via graphql-ws (add ws + graphql-ws packages)
|   +-- NO  --> SSE (default, zero config, works through proxies)
+-- NO  --> No subscription setup needed

Plugin Selection

Feature available as Yoga-specific plugin?
+-- YES --> Use Yoga plugin (HTTP-level hooks, can skip execution)
+-- NO  --> Use Envelop plugin (GraphQL execution-level hooks)

Yoga-Specific Plugins (Prefer Over Envelop)

PluginPackageWhy Yoga-specific
Response Cache@graphql-yoga/plugin-response-cacheSkips execution for cached queries
Persisted Operations@graphql-yoga/plugin-persisted-operationsRejects unknown operations at HTTP layer
Defer/Stream@graphql-yoga/plugin-defer-streamStreams via HTTP chunked encoding
CSRF Prevention@graphql-yoga/plugin-csrf-preventionRequires custom header before parsing
GraphQL SSE@graphql-yoga/plugin-graphql-sseSingle-connection SSE mode

</decision_framework>


<red_flags>

RED FLAGS

High Priority:

  • Importing GraphQLError from graphql-yoga instead of graphql -- wrong package, will fail
  • Passing typeDefs/resolvers object directly to createYoga without createSchema -- not supported in v5
  • Using an Envelop plugin when a Yoga-specific equivalent exists -- misses HTTP-level optimizations (the Yoga response cache skips parsing entirely; the Envelop equivalent cannot)
  • Throwing plain Error in resolvers expecting clients to see the message -- masked to "Unexpected error." in production

Medium Priority:

  • Not configuring CORS origins for production -- default is *, which should be locked down
  • Using in-memory PubSub across multiple server instances -- events won't propagate (use Redis-backed createRedisEventTarget)
  • Missing graphql peer dependency -- graphql-yoga requires graphql as a peer, install both
  • Calling createSchema with no schema at all -- Yoga requires a schema; it does not infer one

Gotchas & Edge Cases:

  • YogaInitialContext.request is a Fetch API Request, not a Node.js IncomingMessage -- use request.headers.get(), not req.headers
  • Plugin execution order changed in v5 -- plugins added via addPlugin in onPluginInit now execute immediately after the adding plugin, not last
  • useResponseCache session callback must return a string (user ID) for PRIVATE scope or null for public -- returning undefined breaks caching
  • SSE subscriptions go through HTTP (text/event-stream) -- some proxies may buffer events; set X-Accel-Buffering: no for Nginx
  • File scalar in uploads gives you a WHATWG File object -- use .text(), .arrayBuffer(), or .stream() methods (not Node.js Buffer directly)
  • Yoga's built-in GraphiQL is enabled by default -- disable with graphiql: false in production
  • maskedErrors set to false disables ALL masking including stack traces -- use custom maskError function instead for selective exposure
  • CORS credentials: true with origin: '*' is rejected by browsers per the Fetch spec -- specify exact origins

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

All code must follow project conventions in CLAUDE.md

(You MUST import GraphQLError from 'graphql', NOT from 'graphql-yoga' -- it is the standard graphql-js export)

(You MUST prefer Yoga-specific plugins over Envelop equivalents -- Yoga plugins operate at the HTTP layer and can skip GraphQL execution entirely for cached/persisted results)

(You MUST use createSchema from 'graphql-yoga' for schema-first -- passing raw typeDefs/resolvers objects directly to createYoga is not supported in v5)

(You MUST use named constants for all numeric values -- timeouts, TTLs, port numbers, limits)

Failure to follow these rules will cause import errors, missed performance optimizations, and information leakage through unmasked errors.

</critical_reminders>

What ships with it: 7 files

34.7 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.