agentsclimarketplace

Api graphql apollo server

Skill agents-inc/skills/dist/plugins/api-graphql-apollo-server/skills/api-graphql-apollo-server

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-apollo-server

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 API server with Apollo Server — schema, resolvers, context, error handling, data sources, plugins

SKILL.md

14.6 KB, as published. Nobody here has run it

GraphQL API with Apollo Server

Quick Guide: Use @apollo/server (v5) for schema-first GraphQL APIs. Define schemas with SDL (typeDefs), implement field population with resolvers, share per-request state via the context function, and handle errors with GraphQLError + extension codes. Use startStandaloneServer for quick setups or integrate with your HTTP framework for production. DataLoader solves the N+1 problem. Plugins hook into the request lifecycle for logging, auth, and performance.


<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 from @apollo/server -- NOT the deprecated apollo-server or apollo-server-express packages)

(You MUST create new data source and DataLoader instances per request in the context function -- sharing across requests causes data leaks)

(You MUST throw GraphQLError (from graphql) with extension codes for client-facing errors -- generic Error exposes stack traces)

(You MUST use ApolloServerPluginDrainHttpServer when integrating with an HTTP framework -- without it the server doesn't shut down gracefully)

</critical_requirements>


Auto-detection: Apollo Server, @apollo/server, ApolloServer, startStandaloneServer, expressMiddleware, GraphQLError, typeDefs, resolvers, contextValue, DataLoader, RESTDataSource, @apollo/datasource-rest, ApolloServerPlugin, buildSubgraphSchema, @apollo/subgraph, graphql-ws, PubSub, formatError, gql tag

When to use:

  • Building a GraphQL API with schema-first (SDL) design
  • Defining typed resolvers with shared context (auth, data sources)
  • Wrapping REST APIs or databases behind a unified GraphQL layer
  • Implementing real-time features with subscriptions (via graphql-ws)
  • Building federated subgraphs with @apollo/subgraph
  • Adding lifecycle hooks with plugins (logging, auth, tracing)

When NOT to use:

  • Simple REST APIs without nested data relationships (a REST framework is simpler)
  • APIs consumed only by one client you control with no query flexibility needs
  • Performance-critical APIs where schema overhead matters (consider a code-first approach)

Key patterns covered:

  • Server setup with startStandaloneServer and framework middleware integration
  • Resolver structure, arguments (parent, args, contextValue, info), and chains
  • Context function for per-request state (auth tokens, data sources, DataLoaders)
  • Error handling with GraphQLError, built-in codes, and formatError
  • RESTDataSource for wrapping REST APIs with caching and deduplication
  • DataLoader for batching and deduplication (N+1 problem)
  • Custom plugins with server-level and request-level lifecycle hooks
  • Subscriptions with graphql-ws and WebSocket server
  • Federation subgraph setup with @apollo/subgraph

Detailed Resources:


<philosophy>

Philosophy

Apollo Server follows a schema-first approach: define your API contract in SDL, then implement resolvers to populate each field. The schema is the single source of truth for your API shape, documentation, and type system.

Core principles:

  1. Schema as contract -- SDL defines what clients can query before implementation begins
  2. Thin resolvers -- Resolvers orchestrate data fetching but delegate to data sources and services
  3. Per-request context -- Each operation gets fresh data source instances and auth state via the context function
  4. Graceful error handling -- GraphQLError with extension codes communicates errors without leaking internals

Use Apollo Server when:

  • You need a unified API layer over multiple data sources (REST, DB, services)
  • Clients benefit from querying exactly the data they need (mobile, varied frontends)
  • Schema documentation and introspection matter for developer experience
  • You want lifecycle plugins for observability, auth, and caching

Use simpler approaches when:

  • A single REST endpoint suffices for your use case
  • You have no nested data relationships worth expressing in a graph
  • The overhead of schema definition and resolver wiring doesn't justify the flexibility
</philosophy>
<patterns>

Core Patterns

Pattern 1: Server Setup

Two approaches: startStandaloneServer for quick/simple setups, or framework middleware integration for production.

import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";

const server = new ApolloServer({ typeDefs, resolvers });

const DEFAULT_PORT = 4000;

const { url } = await startStandaloneServer(server, {
  context: async ({ req }) => ({
    token: req.headers.authorization,
  }),
  listen: { port: DEFAULT_PORT },
});

Why good: minimal boilerplate for development, context function provides per-request auth state

For production with an HTTP framework, use expressMiddleware (from @as-integrations/express4 or @as-integrations/express5) with ApolloServerPluginDrainHttpServer for graceful shutdown.

See examples/core.md for both setup patterns with full TypeScript types.


Pattern 2: Resolver Structure and Arguments

Resolvers receive four arguments: parent (return value from parent resolver), args (field arguments), contextValue (shared per-request state), and info (operation metadata).

const resolvers = {
  Query: {
    user: async (_parent, args, contextValue) => {
      return contextValue.dataSources.usersAPI.getUser(args.id);
    },
  },
  User: {
    posts: async (parent, _args, contextValue) => {
      return contextValue.dataSources.postsAPI.getPostsByAuthor(parent.id);
    },
  },
};

Why good: parent chaining enables nested queries without client round-trips, data source access through context keeps resolvers thin

See examples/core.md for full resolver patterns with type safety.


Pattern 3: Context Function

The context function runs for every operation. Use it to create per-request data sources, extract auth, and set up DataLoaders.

interface MyContext {
  token: string | undefined;
  dataSources: {
    usersAPI: UsersAPI;
    postsAPI: PostsAPI;
  };
}

const server = new ApolloServer<MyContext>({ typeDefs, resolvers });

Critical: Create new data source instances per request. Sharing instances across requests causes stale data and leaks between users.

See examples/core.md for complete context setup.


Pattern 4: Error Handling with GraphQLError

Throw GraphQLError (from the graphql package) with extension codes for structured client errors. Use formatError to sanitize errors before sending.

import { GraphQLError } from "graphql";

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

Built-in codes (from ApolloServerErrorCode): GRAPHQL_PARSE_FAILED, GRAPHQL_VALIDATION_FAILED, BAD_USER_INPUT, INTERNAL_SERVER_ERROR, BAD_REQUEST, PERSISTED_QUERY_NOT_FOUND.

See examples/core.md for formatError, custom codes, and auth error patterns.


Pattern 5: RESTDataSource

Wrap REST APIs with @apollo/datasource-rest for built-in caching, request deduplication, and HTTP method helpers.

import { RESTDataSource } from "@apollo/datasource-rest";

class MoviesAPI extends RESTDataSource {
  override baseURL = "https://movies-api.example.com/";

  async getMovie(id: string): Promise<Movie> {
    return this.get<Movie>(`movies/${encodeURIComponent(id)}`);
  }
}

Two-layer caching: (1) request deduplication prevents duplicate GET calls within a single operation, (2) HTTP response caching honors cache-control headers.

See examples/data-sources.md for RESTDataSource methods, custom caching, and willSendRequest.


Pattern 6: DataLoader for N+1 Prevention

Use DataLoader to batch and deduplicate database or API calls within a single GraphQL operation.

import DataLoader from "dataloader";

const userLoader = new DataLoader<string, User>(async (ids) => {
  const users = await db.users.findMany({ where: { id: { in: [...ids] } } });
  return ids.map((id) => users.find((u) => u.id === id) ?? new Error(`User ${id} not found`));
});

Critical: Create new DataLoader instances per request (in the context function). DataLoader caches results for the request lifetime -- sharing across requests serves stale data.

See examples/data-sources.md for DataLoader setup, batching patterns, and integration with context.


Pattern 7: Custom Plugins

Plugins hook into server and request lifecycle events. Use them for logging, auth checks, performance tracing, and error reporting.

import type { ApolloServerPlugin } from "@apollo/server";

const loggingPlugin: ApolloServerPlugin<MyContext> = {
  async requestDidStart(requestContext) {
    const start = Date.now();
    return {
      async willSendResponse() {
        const duration = Date.now() - start;
        console.log(`Operation took ${duration}ms`);
      },
    };
  },
};

Key lifecycle events: serverWillStart, requestDidStart, parsingDidStart, validationDidStart, executionDidStart, didEncounterErrors, willSendResponse.

See examples/advanced.md for complete plugin patterns.


Pattern 8: Subscriptions with graphql-ws

Apollo Server does not include a built-in WebSocket transport. Use graphql-ws + ws for real-time subscriptions alongside your HTTP server.

import { WebSocketServer } from "ws";
import { useServer } from "graphql-ws/use/ws";

const wsServer = new WebSocketServer({ server: httpServer, path: "/subscriptions" });
const serverCleanup = useServer({ schema }, wsServer);

Note: startStandaloneServer does not support subscriptions -- use framework middleware integration instead. The in-memory PubSub from graphql-subscriptions is for development only; use a distributed pub/sub system in production.

See examples/advanced.md for complete subscription setup with drain plugins.


Pattern 9: Federation Subgraph

Use @apollo/subgraph to build a subgraph that participates in a federated supergraph. Entities use @key directives and __resolveReference resolvers.

import { buildSubgraphSchema } from "@apollo/subgraph";

const server = new ApolloServer({
  schema: buildSubgraphSchema({ typeDefs, resolvers }),
});

Key concepts: @key designates entity identity fields, __resolveReference fetches entities by their key fields, extend type contributes fields from other subgraphs.

See examples/advanced.md for federation schema and reference resolver patterns.

</patterns>

<red_flags>

RED FLAGS

High Priority:

  • Importing from deprecated packages (apollo-server, apollo-server-express) -- use @apollo/server exclusively
  • Sharing data source or DataLoader instances across requests -- causes stale data and cross-user leaks; create new instances in the context function
  • Throwing generic Error from resolvers -- exposes stack traces to clients; use GraphQLError with extension codes
  • Missing ApolloServerPluginDrainHttpServer when using framework integration -- server won't shut down gracefully, leaving connections hanging
  • Calling expressMiddleware before server.start() -- throws an error; start() must complete first

Medium Priority:

  • Using c.req.params instead of resolver args -- bypasses GraphQL argument validation
  • No pagination limits on list resolvers -- returns entire datasets; always enforce max limits
  • In-memory PubSub in production -- only works for a single server instance; use a distributed system
  • Missing encodeURIComponent on dynamic URL segments in RESTDataSource -- path traversal vulnerability
  • Not using formatError to sanitize errors -- internal error messages and stack traces leak to clients in development mode

Gotchas & Edge Cases:

  • Default resolvers: Apollo Server auto-resolves fields matching property names on the parent object -- you don't need explicit resolvers for simple property access
  • contextValue is shared: Never destructively modify contextValue in resolvers -- other resolvers in the same operation share the object
  • Resolver return value of undefined: Triggers the default resolver to try accessing a property on the parent -- may cause unexpected behavior if the parent doesn't have that field
  • Introspection disabled in production: By default, introspection is off when NODE_ENV=production -- override with introspection: true if needed
  • Variable coercion errors: In v5, malformed variables return HTTP 400 by default (v4 returned 200) -- existing clients may need updates
  • Express integration in v5: Import expressMiddleware from @as-integrations/express4 or @as-integrations/express5 (not from @apollo/server/express4 which was removed)
  • Subscription resolvers: Must return an AsyncIterator from subscribe, not a direct value -- the resolve function (optional) transforms the event payload
  • Plugin lifecycle: All plugin methods are async except willResolveField and schemaDidLoadOrUpdate

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

All code must follow project conventions in CLAUDE.md

(You MUST import from @apollo/server -- NOT the deprecated apollo-server or apollo-server-express packages)

(You MUST create new data source and DataLoader instances per request in the context function -- sharing across requests causes data leaks)

(You MUST throw GraphQLError (from graphql) with extension codes for client-facing errors -- generic Error exposes stack traces)

(You MUST use ApolloServerPluginDrainHttpServer when integrating with an HTTP framework -- without it the server doesn't shut down gracefully)

Failure to follow these rules will cause data leaks between users, expose internal errors to clients, and prevent graceful shutdown.

</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.