Overview
Build a GraphQL API with Mercurius, Fastify's official GraphQL adapter. Supports subscriptions out of the box.
Features
- Mercurius integration
- GraphQL subscriptions support
- GraphiQL playground in development
- Context for authentication
- Error handler integration
Installation
npx hanma add fastify-graphql-server --framework fastify
Dependencies
fastify, mercurius, graphql
Code
import Fastify, { FastifyInstance } from "fastify";
import mercurius from "mercurius";
// Type definitions
const schema = `
type Query {
hello(name: String): String!
health: HealthStatus!
}
type Mutation {
echo(message: String!): EchoResponse!
}
type Subscription {
countdown(from: Int!): Int!
}
type HealthStatus {
status: String!
timestamp: String!
uptime: Float!
}
type EchoResponse {
message: String!
timestamp: String!
}
`;
// Resolvers
const resolvers = {
Query: {
hello: (_: unknown, { name }: { name?: string }) => {
return `Hello, ${name ?? "World"}!`;
},
health: () => ({
status: "healthy",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
}),
},
Mutation: {
echo: (_: unknown, { message }: { message: string }) => ({
message,
timestamp: new Date().toISOString(),
}),
},
Subscription: {
countdown: {
subscribe: async function* (_: unknown, { from }: { from: number }) {
for (let i = from; i >= 0; i--) {
await new Promise((resolve) => setTimeout(resolve, 1000));
yield { countdown: i };
}
},
},
},
};
// Context type for authentication
interface GraphQLContext {
user?: {
id: string;
email: string;
roles: string[];
};
}
export async function createGraphQLServer(): Promise<FastifyInstance> {
const app = Fastify({
logger: {
level: process.env.LOG_LEVEL ?? "info",
},
});
await app.register(mercurius, {
schema,
resolvers,
subscription: true,
graphiql: process.env.NODE_ENV !== "production",
context: (request): GraphQLContext => {
// Extract user from JWT or session here
// const token = request.headers.authorization?.replace("Bearer ", "");
return {
// user: decoded user from token
};
},
errorHandler: (error, request, reply) => {
app.log.error({ error, path: request.url }, "GraphQL error");
// Don't expose internal errors in production
if (process.env.NODE_ENV === "production") {
reply.send({
errors: [{ message: "An error occurred" }],
});
} else {
reply.send({
errors: [{ message: error.message, stack: error.stack }],
});
}
},
});
// Health check
app.get("/health", async () => ({
status: "healthy",
graphql: "/graphql",
graphiql: process.env.NODE_ENV !== "production" ? "/graphiql" : "disabled",
}));
return app;
}
// Usage:
// const app = await createGraphQLServer();
// await app.listen({ port: 4000 });
// GraphQL playground available at http://localhost:4000/graphiql
Usage
import { createGraphQLServer } from './graphql-server';
const app = await createGraphQLServer();
await app.listen({ port: 4000 });
Dependencies
fastifymercuriusgraphql
Frequently Asked Questions
How do I install GraphQL Server (Mercurius)?
Run the following command:
npx hanma add fastify-graphql-server --framework fastifyWhat dependencies are required?
This snippet requires: fastify, mercurius, graphql. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to
src/graphql-server.ts.Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.