fix(#27): Implement uniform error handling with standardized format
Some checks are pending
Docker Test / test (push) Waiting to run
Some checks are pending
Docker Test / test (push) Waiting to run
This commit is contained in:
parent
ad03a47ed8
commit
e4098e3e2a
3 changed files with 91 additions and 10 deletions
|
|
@ -2,6 +2,7 @@ import { Router } from 'express';
|
|||
import { z } from 'zod';
|
||||
import { pool } from '../db/connection.js';
|
||||
import { requireAuth } from '../middleware/auth.js';
|
||||
import { createError, sendError } from '../utils/errorHandler.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
|
|
@ -19,7 +20,7 @@ const getDealParticipants = async (dealId) => {
|
|||
return rows[0] || null;
|
||||
} catch (error) {
|
||||
console.error('Database error while fetching deal participants for dealId:', dealId, error);
|
||||
throw new Error('Database error while fetching deal participants');
|
||||
throw createError('DATABASE_ERROR', 'Database error while fetching deal participants');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -31,20 +32,20 @@ router.post('/request', requireAuth, async (req, res) => {
|
|||
}).safeParse(req.body);
|
||||
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ error: 'Invalid input data', details: parsed.error.flatten() });
|
||||
throw createError('VALIDATION_ERROR', 'Invalid input data', parsed.error.flatten());
|
||||
}
|
||||
|
||||
const { dealId, targetUserId } = parsed.data;
|
||||
const deal = await getDealParticipants(dealId);
|
||||
|
||||
if (!deal) {
|
||||
return res.status(404).json({ error: 'Deal not found' });
|
||||
throw createError('NOT_FOUND_ERROR', 'Deal not found');
|
||||
}
|
||||
|
||||
const participants = [deal.requester_id, deal.helper_id];
|
||||
|
||||
if (!participants.includes(req.user.userId) || !participants.includes(targetUserId) || req.user.userId === targetUserId) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
throw createError('AUTHORIZATION_ERROR', 'Forbidden');
|
||||
}
|
||||
|
||||
const [existing] = await pool.query(
|
||||
|
|
@ -54,7 +55,7 @@ router.post('/request', requireAuth, async (req, res) => {
|
|||
);
|
||||
|
||||
if (existing.length) {
|
||||
return res.status(409).json({ error: 'Request already exists' });
|
||||
throw createError('CONFLICT_ERROR', 'Request already exists');
|
||||
}
|
||||
|
||||
const [result] = await pool.query(
|
||||
|
|
@ -66,7 +67,7 @@ router.post('/request', requireAuth, async (req, res) => {
|
|||
res.status(201).json({ id: result.insertId });
|
||||
} catch (error) {
|
||||
console.error('Error in contacts request route:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
sendError(res, error);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ router.post('/respond', requireAuth, async (req, res) => {
|
|||
}).safeParse(req.body);
|
||||
|
||||
if (!parsed.success) {
|
||||
return res.status(400).json({ error: 'Invalid input data', details: parsed.error.flatten() });
|
||||
throw createError('VALIDATION_ERROR', 'Invalid input data', parsed.error.flatten());
|
||||
}
|
||||
|
||||
const { requestId, accept } = parsed.data;
|
||||
|
|
@ -90,11 +91,11 @@ router.post('/respond', requireAuth, async (req, res) => {
|
|||
const row = rows[0];
|
||||
|
||||
if (!row) {
|
||||
return res.status(404).json({ error: 'Request not found' });
|
||||
throw createError('NOT_FOUND_ERROR', 'Request not found');
|
||||
}
|
||||
|
||||
if (row.target_id !== req.user.userId) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
throw createError('AUTHORIZATION_ERROR', 'Forbidden');
|
||||
}
|
||||
|
||||
if (accept) {
|
||||
|
|
@ -106,7 +107,7 @@ router.post('/respond', requireAuth, async (req, res) => {
|
|||
res.json({ status: 'rejected' });
|
||||
} catch (error) {
|
||||
console.error('Error in contacts respond route:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
sendError(res, error);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
56
backend/src/utils/errorHandler.js
Normal file
56
backend/src/utils/errorHandler.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* Einheitliche Fehlerstruktur für die Anwendung
|
||||
*/
|
||||
export const createError = (code, message, details = null) => {
|
||||
const error = new Error(message);
|
||||
error.code = code;
|
||||
error.details = details;
|
||||
error.requestId = generateRequestId();
|
||||
return error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generiert eine eindeutige Request-ID
|
||||
*/
|
||||
export const generateRequestId = () => {
|
||||
return 'req_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sendet eine konsistente Fehlermeldung an den Client
|
||||
*/
|
||||
export const sendError = (res, error) => {
|
||||
const errorResponse = {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
details: error.details,
|
||||
requestId: error.requestId
|
||||
};
|
||||
|
||||
// Logge den Fehler für Debugging
|
||||
console.error('API Error:', errorResponse);
|
||||
|
||||
res.status(getStatusCode(error.code)).json(errorResponse);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bestimmt den HTTP-Statuscode basierend auf dem Fehlercode
|
||||
*/
|
||||
export const getStatusCode = (code) => {
|
||||
switch (code) {
|
||||
case 'VALIDATION_ERROR':
|
||||
return 400;
|
||||
case 'AUTHENTICATION_ERROR':
|
||||
return 401;
|
||||
case 'AUTHORIZATION_ERROR':
|
||||
return 403;
|
||||
case 'NOT_FOUND_ERROR':
|
||||
return 404;
|
||||
case 'CONFLICT_ERROR':
|
||||
return 409;
|
||||
case 'DATABASE_ERROR':
|
||||
return 500;
|
||||
default:
|
||||
return 500;
|
||||
}
|
||||
};
|
||||
24
docs/adr/001-error-handling.md
Normal file
24
docs/adr/001-error-handling.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# 1. Einheitliches Fehlerformat
|
||||
|
||||
## Status
|
||||
|
||||
Akzeptiert
|
||||
|
||||
## Kontext
|
||||
|
||||
Die Anwendung hat momentan unklare und inkonsistente Fehlermeldungen, was die UX und das Debugging erschwert. Es ist notwendig, ein einheitliches Format für Fehlermeldungen zu definieren.
|
||||
|
||||
## Entscheidung
|
||||
|
||||
Wir implementieren ein einheitliches Fehlerformat mit folgenden Feldern:
|
||||
|
||||
- `code`: Ein eindeutiger Fehlercode (z.B. `VALIDATION_ERROR`, `DATABASE_ERROR`)
|
||||
- `message`: Eine menschenlesbare Fehlermeldung
|
||||
- `details`: Zusätzliche technische Details zur Fehlerursache
|
||||
- `requestId`: Eine eindeutige ID für die Anfrage, um Debugging zu erleichtern
|
||||
|
||||
## Konsequenzen
|
||||
|
||||
- Verbesserte UX durch konsistente Fehlermeldungen
|
||||
- Einfacheres Debugging durch einheitliche Fehlerstruktur
|
||||
- Bessere Dokumentation der API-Fehler
|
||||
Loading…
Add table
Add a link
Reference in a new issue