|
import { Request, Response, NextFunction } from 'express' |
|
import { Prisma } from '@prisma/client' |
|
|
|
export interface AppError extends Error { |
|
statusCode?: number |
|
code?: string |
|
} |
|
|
|
export const errorHandler = ( |
|
error: AppError, |
|
req: Request, |
|
res: Response, |
|
next: NextFunction |
|
) => { |
|
console.error('Error:', error) |
|
|
|
|
|
let statusCode = error.statusCode || 500 |
|
let message = error.message || 'Internal server error' |
|
let code = error.code || 'INTERNAL_ERROR' |
|
|
|
|
|
if (error instanceof Prisma.PrismaClientKnownRequestError) { |
|
switch (error.code) { |
|
case 'P2002': |
|
statusCode = 409 |
|
message = 'Resource already exists' |
|
code = 'DUPLICATE_ERROR' |
|
break |
|
case 'P2025': |
|
statusCode = 404 |
|
message = 'Resource not found' |
|
code = 'NOT_FOUND' |
|
break |
|
case 'P2003': |
|
statusCode = 400 |
|
message = 'Invalid reference' |
|
code = 'INVALID_REFERENCE' |
|
break |
|
default: |
|
statusCode = 400 |
|
message = 'Database error' |
|
code = 'DATABASE_ERROR' |
|
} |
|
} |
|
|
|
|
|
if (error.name === 'ValidationError') { |
|
statusCode = 400 |
|
code = 'VALIDATION_ERROR' |
|
} |
|
|
|
|
|
if (error.name === 'JsonWebTokenError') { |
|
statusCode = 401 |
|
message = 'Invalid token' |
|
code = 'INVALID_TOKEN' |
|
} |
|
|
|
if (error.name === 'TokenExpiredError') { |
|
statusCode = 401 |
|
message = 'Token expired' |
|
code = 'TOKEN_EXPIRED' |
|
} |
|
|
|
|
|
if (error.code === 'LIMIT_FILE_SIZE') { |
|
statusCode = 413 |
|
message = 'File too large' |
|
code = 'FILE_TOO_LARGE' |
|
} |
|
|
|
if (error.code === 'LIMIT_FILE_COUNT') { |
|
statusCode = 413 |
|
message = 'Too many files' |
|
code = 'TOO_MANY_FILES' |
|
} |
|
|
|
|
|
if (process.env.NODE_ENV === 'production' && statusCode === 500) { |
|
message = 'Internal server error' |
|
} |
|
|
|
res.status(statusCode).json({ |
|
success: false, |
|
error: message, |
|
code, |
|
...(process.env.NODE_ENV === 'development' && { stack: error.stack }) |
|
}) |
|
} |
|
|
|
export const notFoundHandler = (req: Request, res: Response) => { |
|
res.status(404).json({ |
|
success: false, |
|
error: 'Route not found', |
|
code: 'NOT_FOUND' |
|
}) |
|
} |
|
|
|
export const asyncHandler = (fn: Function) => { |
|
return (req: Request, res: Response, next: NextFunction) => { |
|
Promise.resolve(fn(req, res, next)).catch(next) |
|
} |
|
} |
|
|