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
This commit is contained in:
Torsten Schulz (local)
2025-09-24 11:59:13 +02:00
9 changed files with 2998 additions and 1681 deletions

View File

@@ -1,71 +1,139 @@
/**
* Zentrale Fehlerbehandlung für die Anwendung
*/
class ErrorHandler {
/**
* Error in HTTP Response umwandeln
* 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)
*/
handleError(error, res) {
console.error('Error:', error);
// Validation Errors
if (error.message.startsWith('VALIDATION_ERROR:')) {
const message = error.message.replace('VALIDATION_ERROR: ', '');
return res.status(400).json({
success: false,
message: message,
type: 'VALIDATION_ERROR'
});
}
// Business Logic Errors
switch (error.message) {
case 'USER_NOT_FOUND':
return res.status(404).json({
success: false,
message: 'Benutzer nicht gefunden',
type: 'NOT_FOUND'
});
case 'INVALID_CURRENT_PASSWORD':
return res.status(400).json({
success: false,
message: 'Aktuelles Passwort ist falsch',
type: 'INVALID_PASSWORD'
});
case 'EMAIL_ALREADY_EXISTS':
return res.status(409).json({
success: false,
message: 'E-Mail-Adresse bereits vorhanden',
type: 'DUPLICATE_EMAIL'
});
default:
return res.status(500).json({
success: false,
message: 'Ein interner Fehler ist aufgetreten',
type: 'INTERNAL_ERROR'
});
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);
}
/**
* Success Response erstellen
* 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)
*/
successResponse(res, data, message = 'Erfolgreich', statusCode = 200) {
return res.status(statusCode).json({
static successResponse(res, data, message = 'Erfolgreich', statusCode = 200) {
const response = {
success: true,
message: message,
data: data
});
message,
data,
timestamp: new Date().toISOString()
};
return res.status(statusCode).json(response);
}
/**
* Async Error Wrapper für Controller
* Wrapper für async Controller-Funktionen mit automatischer Fehlerbehandlung
* @param {Function} fn - Async Controller-Funktion
* @returns {Function} - Wrapped Controller-Funktion
*/
asyncHandler(fn) {
static asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(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 = new ErrorHandler();
module.exports = ErrorHandler;