Files
miriamgemeinde/utils/ErrorHandler.js
Torsten Schulz (local) 7861b9cffb Merge-Konflikt aufgelöst: AuthService und ErrorHandler wiederhergestellt
- AuthService mit allen Methoden (register, login, forgotPassword, resetPassword, logout)
- ErrorHandler für zentrale Fehlerbehandlung
- authController.js auf neue Clean Code Architektur umgestellt
- Alle Authentifizierungsendpunkte verwenden jetzt Service Layer Pattern
2025-09-24 11:59:13 +02:00

139 lines
3.6 KiB
JavaScript

/**
* Zentrale Fehlerbehandlung für die Anwendung
*/
class ErrorHandler {
/**
* Erstellt eine standardisierte Fehlerantwort
* @param {Object} res - Express Response Objekt
* @param {number} statusCode - HTTP Status Code
* @param {string} message - Fehlermeldung
* @param {Object} details - Zusätzliche Fehlerdetails (optional)
*/
static errorResponse(res, statusCode, message, details = null) {
const error = {
success: false,
message,
timestamp: new Date().toISOString()
};
if (details) {
error.details = details;
}
console.error(`[${statusCode}] ${message}`, details ? details : '');
return res.status(statusCode).json(error);
}
/**
* Erstellt eine erfolgreiche Antwort
* @param {Object} res - Express Response Objekt
* @param {Object} data - Antwortdaten
* @param {string} message - Erfolgsmeldung
* @param {number} statusCode - HTTP Status Code (default: 200)
*/
static successResponse(res, data, message = 'Erfolgreich', statusCode = 200) {
const response = {
success: true,
message,
data,
timestamp: new Date().toISOString()
};
return res.status(statusCode).json(response);
}
/**
* Wrapper für async Controller-Funktionen mit automatischer Fehlerbehandlung
* @param {Function} fn - Async Controller-Funktion
* @returns {Function} - Wrapped Controller-Funktion
*/
static asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch((error) => {
console.error('Unhandled error in async handler:', error);
this.errorResponse(res, 500, 'Ein unerwarteter Fehler ist aufgetreten', {
error: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
});
};
}
/**
* Behandelt Sequelize-Validierungsfehler
* @param {Object} error - Sequelize Error
* @returns {Object} - Standardisierte Fehlerantwort
*/
static handleSequelizeError(error) {
if (error.name === 'SequelizeValidationError') {
const validationErrors = error.errors.map(err => ({
field: err.path,
message: err.message,
value: err.value
}));
return {
statusCode: 400,
message: 'Validierungsfehler',
details: { validationErrors }
};
}
if (error.name === 'SequelizeUniqueConstraintError') {
return {
statusCode: 409,
message: 'Eindeutigkeitsverletzung',
details: { field: error.errors[0]?.path }
};
}
if (error.name === 'SequelizeForeignKeyConstraintError') {
return {
statusCode: 400,
message: 'Referenzfehler',
details: { field: error.fields[0] }
};
}
if (error.name === 'SequelizeDatabaseError') {
return {
statusCode: 500,
message: 'Datenbankfehler',
details: { original: error.original?.message }
};
}
return {
statusCode: 500,
message: 'Datenbankfehler',
details: { error: error.message }
};
}
/**
* Behandelt JWT-Fehler
* @param {Object} error - JWT Error
* @returns {Object} - Standardisierte Fehlerantwort
*/
static handleJWTError(error) {
if (error.name === 'JsonWebTokenError') {
return {
statusCode: 401,
message: 'Ungültiger Token'
};
}
if (error.name === 'TokenExpiredError') {
return {
statusCode: 401,
message: 'Token abgelaufen'
};
}
return {
statusCode: 401,
message: 'Authentifizierungsfehler'
};
}
}
module.exports = ErrorHandler;