Claude-skill-registry graphql-apollo-server
Build production GraphQL servers with Apollo Server, plugins, and federation
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/graphql-apollo-server" ~/.claude/skills/majiayu000-claude-skill-registry-graphql-apollo-server && rm -rf "$T"
manifest:
skills/data/graphql-apollo-server/SKILL.mdsource content
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 | | Core server |
| Express | | Express integration |
| Plugins | | Extensibility |
| Federation | | 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
- Resolver implementationgraphql-resolvers
- Security configurationgraphql-security
- Type generationgraphql-codegen
Related Agent
- For detailed guidance04-graphql-apollo-server