js

Build Type-Safe REST APIs with Fastify, Zod, and Prisma: Complete TypeScript Guide

Learn to build production-ready REST APIs with Fastify, Zod & Prisma. Complete TypeScript guide with validation, testing & advanced features.

Build Type-Safe REST APIs with Fastify, Zod, and Prisma: Complete TypeScript Guide

Recently, I struggled with API inconsistencies in a large-scale project—missing fields, unexpected data types, and validation gaps that caused production issues. This frustration led me to explore how Fastify, Zod, and Prisma could create truly type-safe REST APIs in TypeScript. What if you could catch data errors at compile time rather than runtime? Let’s build a solution together.

First, we set up our environment. I prefer a clean workspace with clear dependencies:

npm init -y
npm install fastify @fastify/type-provider-typebox prisma zod
npm install -D typescript @types/node tsx

Our tsconfig.json establishes strict TypeScript rules. Notice strict: true—it’s non-negotiable for type safety:

{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "outDir": "./dist"
  }
}

For database modeling, Prisma’s schema language shines. Here’s how we define a User model with relations. Did you notice how @relation links models explicitly?

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  posts     Post[]
}

model Post {
  id       String @id @default(cuid())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId String
}

Run npx prisma generate to create the TypeScript client. This gives us auto-completion for database queries.

Validation is where Zod excels. Instead of loose interfaces, we define strict schemas:

import { z } from 'zod';

const UserSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
});

When combined with Fastify’s type provider, we get end-to-end type inference:

import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';

const app = fastify().withTypeProvider<TypeBoxTypeProvider>();

app.post('/users', {
  schema: {
    body: UserSchema
  },
  handler: async (req) => {
    // req.body is fully typed!
    return prisma.user.create({ data: req.body });
  }
});

For pagination, consider this reusable pattern. How might we extend this for complex filters?

const PaginationSchema = z.object({
  page: z.number().int().positive().default(1),
  limit: z.number().min(1).max(100).default(20)
});

app.get('/posts', {
  schema: { querystring: PaginationSchema },
  handler: async (req) => {
    const { page, limit } = req.query;
    return prisma.post.findMany({
      skip: (page - 1) * limit,
      take: limit
    });
  }
});

Error handling needs special attention. We use Fastify hooks:

app.setErrorHandler((error, request, reply) => {
  if (error instanceof z.ZodError) {
    reply.code(400).send({
      error: 'Validation failed',
      details: error.issues
    });
  }
});

Testing becomes straightforward with Vitest:

import { test } from 'vitest';
import app from './app';

test('POST /users rejects invalid emails', async () => {
  const response = await app.inject({
    method: 'POST',
    path: '/users',
    payload: { email: 'not-an-email' }
  });
  expect(response.statusCode).toBe(400);
});

In production, remember these essentials:

# Enable compression and logging
npm install @fastify/compress @fastify/helmet pino-pretty

# In server.ts
app.register(require('@fastify/compress'));
app.register(require('@fastify/helmet'));

This approach caught 90% of our data-related bugs during development. The synergy between Zod’s validation, Prisma’s type-safe queries, and Fastify’s performance creates a robust foundation. Have you considered how type safety could reduce your debugging time?

What challenges have you faced in API development? Share your experiences below—I’d love to hear your solutions. If this resonates with you, please like or share this with others who might benefit.

Keywords: Fastify TypeScript API, Zod schema validation, Prisma ORM integration, type-safe REST API, Fastify Prisma Zod tutorial, TypeScript API development, REST API validation, Prisma database design, Fastify middleware implementation, type-safe API endpoints



Similar Posts
Blog Image
Complete Guide to Integrating Next.js with Prisma ORM for Type-Safe Full-Stack Development

Learn to integrate Next.js with Prisma ORM for type-safe full-stack development. Build powerful web apps with seamless database operations and TypeScript support.

Blog Image
Build Type-Safe Event-Driven Architecture with TypeScript, EventEmitter2, and Redis Complete Guide

Master TypeScript event-driven architecture with EventEmitter2 & Redis. Build scalable, type-safe systems with distributed event handling, error resilience & monitoring best practices.

Blog Image
Complete Next.js Prisma Integration Guide: Build Type-Safe Full-Stack Apps in 2024

Learn to integrate Next.js with Prisma for powerful full-stack development. Build type-safe APIs, streamline database operations, and boost productivity in one codebase.

Blog Image
Build Multi-Tenant SaaS Applications with NestJS, Prisma, and PostgreSQL Row-Level Security

Learn to build scalable multi-tenant SaaS apps with NestJS, Prisma, and PostgreSQL RLS. Complete guide with secure tenant isolation and database-level security. Start building today!

Blog Image
Event-Driven Architecture with RabbitMQ and Node.js: Complete Microservices Communication Guide

Learn to build scalable event-driven microservices with RabbitMQ and Node.js. Master async messaging patterns, error handling, and production deployment strategies.

Blog Image
Build Production-Ready GraphQL APIs with NestJS, Prisma, and Redis: Complete Performance Optimization Guide

Learn to build scalable GraphQL APIs with NestJS, Prisma ORM, and Redis caching. Master authentication, performance optimization, and production deployment.