agentsclimarketplace

Api graphql yoga

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

The official skills marketplace for Agents Inc, an agent composition framework that builds stacks and compiles specialized subagents for Claude Code

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

  • 18 stars18 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.

What its author says it does

Copied from the file, not written here

GraphQL Yoga v5 server, Envelop plugins, subscriptions, error masking

SKILL.md

13.9 KB, 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>

Keep looking

Skills are one crate of 328,083. 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.