103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
import { Request, Response, NextFunction } from 'express';
|
|
import { GenerateImageResponse } from '../types/api';
|
|
|
|
/**
|
|
* Global error handler for the Express application
|
|
*/
|
|
export const errorHandler = (
|
|
error: Error,
|
|
req: Request,
|
|
res: Response,
|
|
next: NextFunction
|
|
) => {
|
|
const timestamp = new Date().toISOString();
|
|
const requestId = req.requestId || 'unknown';
|
|
|
|
// Log the error
|
|
console.error(`[${timestamp}] [${requestId}] ERROR:`, {
|
|
message: error.message,
|
|
stack: error.stack,
|
|
path: req.path,
|
|
method: req.method,
|
|
body: req.body,
|
|
query: req.query
|
|
});
|
|
|
|
// Don't send error response if headers already sent
|
|
if (res.headersSent) {
|
|
return next(error);
|
|
}
|
|
|
|
// Determine error type and status code
|
|
let statusCode = 500;
|
|
let errorMessage = 'Internal server error';
|
|
let errorType = 'INTERNAL_ERROR';
|
|
|
|
if (error.name === 'ValidationError') {
|
|
statusCode = 400;
|
|
errorMessage = error.message;
|
|
errorType = 'VALIDATION_ERROR';
|
|
} else if (error.message.includes('API key') || error.message.includes('authentication')) {
|
|
statusCode = 401;
|
|
errorMessage = 'Authentication failed';
|
|
errorType = 'AUTH_ERROR';
|
|
} else if (error.message.includes('not found') || error.message.includes('404')) {
|
|
statusCode = 404;
|
|
errorMessage = 'Resource not found';
|
|
errorType = 'NOT_FOUND';
|
|
} else if (error.message.includes('timeout') || error.message.includes('503')) {
|
|
statusCode = 503;
|
|
errorMessage = 'Service temporarily unavailable';
|
|
errorType = 'SERVICE_UNAVAILABLE';
|
|
} else if (error.message.includes('overloaded') || error.message.includes('rate limit')) {
|
|
statusCode = 429;
|
|
errorMessage = 'Service overloaded, please try again later';
|
|
errorType = 'RATE_LIMITED';
|
|
}
|
|
|
|
// Create error response
|
|
const errorResponse: GenerateImageResponse = {
|
|
success: false,
|
|
message: 'Request failed',
|
|
error: errorMessage
|
|
};
|
|
|
|
// Add additional debug info in development
|
|
if (process.env.NODE_ENV === 'development') {
|
|
(errorResponse as any).debug = {
|
|
originalError: error.message,
|
|
errorType,
|
|
requestId,
|
|
timestamp
|
|
};
|
|
}
|
|
|
|
console.log(`[${timestamp}] [${requestId}] Sending error response: ${statusCode} - ${errorMessage}`);
|
|
|
|
res.status(statusCode).json(errorResponse);
|
|
};
|
|
|
|
/**
|
|
* 404 handler for unmatched routes
|
|
*/
|
|
export const notFoundHandler = (req: Request, res: Response) => {
|
|
const timestamp = new Date().toISOString();
|
|
const requestId = req.requestId || 'unknown';
|
|
|
|
console.log(`[${timestamp}] [${requestId}] 404 - Route not found: ${req.method} ${req.path}`);
|
|
|
|
const notFoundResponse: GenerateImageResponse = {
|
|
success: false,
|
|
message: 'Route not found',
|
|
error: `The requested endpoint ${req.method} ${req.path} does not exist`
|
|
};
|
|
|
|
res.status(404).json(notFoundResponse);
|
|
};
|
|
|
|
/**
|
|
* Async error wrapper to catch errors in async route handlers
|
|
*/
|
|
export const asyncHandler = (fn: Function) => (req: Request, res: Response, next: NextFunction) => {
|
|
Promise.resolve(fn(req, res, next)).catch(next);
|
|
}; |