graphql-apollo-server

graphql-apollo-server

Build production GraphQL servers with Apollo Server, plugins, and federation

1星標
0分支
更新於 1/5/2026
SKILL.md
readonlyread-only
name
graphql-apollo-server
description

Build production GraphQL servers with Apollo Server, plugins, and federation

version
"2.0.0"

Apollo Server Skill

Deploy production-ready GraphQL APIs

Overview

Learn to build scalable GraphQL servers with Apollo Server 4, including middleware integration, custom plugins, federation, and production best practices.


Quick Reference

Feature Package Purpose
Server @apollo/server Core server
Express @apollo/server/express4 Express integration
Plugins @apollo/server/plugin/* Extensibility
Federation @apollo/subgraph Microservices

Core Setup

1. Basic Server (Express)

import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import express from 'express';
import http from 'http';
import cors from 'cors';

interface Context {
  user: User | null;
  dataSources: DataSources;
}

async function startServer() {
  const app = express();
  const httpServer = http.createServer(app);

  const server = new ApolloServer<Context>({
    typeDefs,
    resolvers,
    plugins: [
      // Graceful shutdown
      ApolloServerPluginDrainHttpServer({ httpServer }),
    ],
  });

  await server.start();

  app.use(
    '/graphql',
    cors({ origin: ['http://localhost:3000'], credentials: true }),
    express.json(),
    expressMiddleware(server, {
      context: async ({ req }) => ({
        user: await getUser(req),
        dataSources: createDataSources(),
      }),
    }),
  );

  httpServer.listen(4000, () => {
    console.log('Server ready at http://localhost:4000/graphql');
  });
}

2. Production Configuration

const server = new ApolloServer<Context>({
  typeDefs,
  resolvers,

  // Error formatting
  formatError: (error) => {
    console.error('GraphQL Error:', error);

    // Hide internal errors in production
    if (process.env.NODE_ENV === 'production') {
      if (error.extensions?.code === 'INTERNAL_SERVER_ERROR') {
        return { message: 'Internal error', extensions: { code: 'INTERNAL_ERROR' } };
      }
    }
    return error;
  },

  // Disable introspection in production
  introspection: process.env.NODE_ENV !== 'production',

  plugins: [
    ApolloServerPluginDrainHttpServer({ httpServer }),
    loggingPlugin,
    complexityPlugin,
  ],
});

3. Custom Plugins

import { ApolloServerPlugin } from '@apollo/server';

// Logging plugin
const loggingPlugin: ApolloServerPlugin<Context> = {
  async requestDidStart({ request, contextValue }) {
    const start = Date.now();
    console.log('Request:', request.operationName);

    return {
      async willSendResponse() {
        console.log(`Completed in ${Date.now() - start}ms`);
      },

      async didEncounterErrors({ errors }) {
        errors.forEach(e => console.error('Error:', e.message));
      },
    };
  },
};

// Query complexity plugin
import { getComplexity, simpleEstimator } from 'graphql-query-complexity';

const complexityPlugin: ApolloServerPlugin<Context> = {
  async requestDidStart() {
    return {
      async didResolveOperation({ schema, document, request }) {
        const complexity = getComplexity({
          schema,
          query: document,
          variables: request.variables,
          estimators: [simpleEstimator({ defaultComplexity: 1 })],
        });

        if (complexity > 1000) {
          throw new GraphQLError('Query too complex');
        }
      },
    };
  },
};

4. Federation (Subgraph)

import { buildSubgraphSchema } from '@apollo/subgraph';
import { gql } from 'graphql-tag';

const typeDefs = gql`
  extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.0",
          import: ["@key", "@shareable", "@external"])

  type Query {
    user(id: ID!): User
  }

  type User @key(fields: "id") {
    id: ID!
    name: String!
    email: String!
  }
`;

const resolvers = {
  Query: {
    user: (_, { id }) => users.find(u => u.id === id),
  },
  User: {
    __resolveReference: (user) => users.find(u => u.id === user.id),
  },
};

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

5. Response Caching

import responseCachePlugin from '@apollo/server-plugin-response-cache';

const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    responseCachePlugin({
      // Cache key includes user ID for personalized data
      sessionId: ({ contextValue }) => contextValue.user?.id || null,
    }),
  ],
});

// Schema hints
const typeDefs = gql`
  type Query {
    # Cache for 1 hour
    popularPosts: [Post!]! @cacheControl(maxAge: 3600)

    # Private, user-specific
    me: User @cacheControl(maxAge: 0, scope: PRIVATE)
  }
`;

6. Health Checks

// Health endpoint
app.get('/health', async (req, res) => {
  const checks = {
    server: 'healthy',
    database: await checkDb(),
    redis: await checkRedis(),
  };

  const healthy = Object.values(checks).every(c => c === 'healthy');
  res.status(healthy ? 200 : 503).json(checks);
});

// Readiness endpoint
app.get('/ready', (req, res) => {
  res.status(serverReady ? 200 : 503).json({ ready: serverReady });
});

Troubleshooting

Issue Cause Solution
CORS errors Missing middleware Add cors() before expressMiddleware
503 on shutdown No drain Add DrainHttpServer plugin
Memory leak Global loaders Create per-request
Slow startup Large schema Use schema caching

Debug Commands

# Test server
curl http://localhost:4000/health

# Test GraphQL
curl -X POST http://localhost:4000/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __typename }"}'

# Introspection
curl -X POST http://localhost:4000/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name } } }"}'

Usage

Skill("graphql-apollo-server")

Related Skills

  • graphql-resolvers - Resolver implementation
  • graphql-security - Security configuration
  • graphql-codegen - Type generation

Related Agent

  • 04-graphql-apollo-server - For detailed guidance

You Might Also Like

Related Skills

gog

gog

169Kdev-api

Google Workspace CLI for Gmail, Calendar, Drive, Contacts, Sheets, and Docs.

openclaw avataropenclaw
獲取
weather

weather

169Kdev-api

Get current weather and forecasts (no API key required).

openclaw avataropenclaw
獲取

Guide for implementing oRPC contract-first API patterns in Dify frontend. Triggers when creating new API contracts, adding service endpoints, integrating TanStack Query with typed contracts, or migrating legacy service calls to oRPC. Use for all API layer work in web/contract and web/service directories.

langgenius avatarlanggenius
獲取
blucli

blucli

92Kdev-api

BluOS CLI (blu) for discovery, playback, grouping, and volume.

moltbot avatarmoltbot
獲取
ordercli

ordercli

92Kdev-api

Foodora-only CLI for checking past orders and active order status (Deliveroo WIP).

moltbot avatarmoltbot
獲取
gifgrep

gifgrep

92Kdev-api

Search GIF providers with CLI/TUI, download results, and extract stills/sheets.

moltbot avatarmoltbot
獲取