From graphql-development-assistant
Build production GraphQL servers with Apollo Server, plugins, and federation
How this skill is triggered — by the user, by Claude, or both
Slash command
/graphql-development-assistant:skills/graphql-apollo-serverThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Deploy production-ready GraphQL APIs
Deploy production-ready GraphQL APIs
Learn to build scalable GraphQL servers with Apollo Server 4, including middleware integration, custom plugins, federation, and production best practices.
| Feature | Package | Purpose |
|---|---|---|
| Server | @apollo/server | Core server |
| Express | @apollo/server/express4 | Express integration |
| Plugins | @apollo/server/plugin/* | Extensibility |
| Federation | @apollo/subgraph | Microservices |
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');
});
}
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,
],
});
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');
}
},
};
},
};
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 }),
});
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)
}
`;
// 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 });
});
| 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 |
# 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 } } }"}'
Skill("graphql-apollo-server")
graphql-resolvers - Resolver implementationgraphql-security - Security configurationgraphql-codegen - Type generation04-graphql-apollo-server - For detailed guidancenpx claudepluginhub pluginagentmarketplace/custom-plugin-graphql --plugin developer-roadmapConfigures Apollo Server 4 with framework integrations, context, plugins, data sources, and production hardening. Useful for setting up or migrating GraphQL APIs.
Guide for building GraphQL servers with Apollo Server 5.x. Covers setup, resolvers, schemas, authentication, plugins, data sources, and troubleshooting.
Provides patterns for building GraphQL APIs with Apollo Server, covering schema design, resolvers, data sources, federation, error handling, and production setup.