Real World Example

Mapping Database Errors

In production, many 500s are really database constraint errors. A filter for Prisma errors turns them into proper client errors; teams at fintechs and marketplaces do this so duplicate signups show "already registered" instead of a crash.

src/prisma/prisma-exception.filter.ts

import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import type { Response } from 'express';

@Catch(Prisma.PrismaClientKnownRequestError)
export class PrismaExceptionFilter implements ExceptionFilter {
  catch(e: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
    const res = host.switchToHttp().getResponse<Response>();
    const map: Record<string, [number, string, string]> = {
      P2002: [HttpStatus.CONFLICT, 'DUPLICATE', `Duplicate value for ${(e.meta?.target as string[])?.join(', ')}`],
      P2025: [HttpStatus.NOT_FOUND, 'NOT_FOUND', 'Record not found'],
      P2003: [HttpStatus.BAD_REQUEST, 'INVALID_REFERENCE', 'Related record does not exist'],
    };
    const [statusCode, code, message] = map[e.code] ?? [HttpStatus.INTERNAL_SERVER_ERROR, 'DB_ERROR', 'Database error'];
    res.status(statusCode).json({ success: false, error: { statusCode, code, message } });
  }
}

Example

curl -X POST http://localhost:3000/auth/register -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"Secret123","name":"Asha"}'

Example output

HTTP/1.1 409 Conflict
{"success":false,"error":{"statusCode":409,"code":"DUPLICATE","message":"Duplicate value for email"}}