This commit is contained in:
seb
2026-07-31 08:34:51 +02:00
parent a95b7f4b1e
commit 797ea59bed
24 changed files with 1151 additions and 130 deletions

86
src/utils/backendError.js Normal file
View File

@@ -0,0 +1,86 @@
const STATUS_TITLES = {
400: 'Ungültige Anfrage',
401: 'Nicht angemeldet',
403: 'Zugriff verweigert',
404: 'Nicht gefunden',
409: 'Konflikt',
422: 'Ungültige Daten',
500: 'Serverfehler',
502: 'Gateway-Fehler',
503: 'Dienst nicht erreichbar',
};
const GENERIC_HTTP_TITLES = new Set([
'not found',
'unauthorized',
'forbidden',
'internal server error',
'bad request',
'service unavailable',
]);
/** Normalize any thrown value into a stable backend error object. */
export function backendErrorFrom(err) {
if (!err) {
return { message: 'Unbekannter Fehler', status: null, path: null, method: null };
}
if (typeof err === 'string') {
return { message: err, status: null, path: null, method: null };
}
if (err.message != null && (err.status != null || err.path != null || err.method != null)) {
return {
message: err.message,
status: err.status ?? null,
path: err.path ?? null,
method: err.method ?? null,
};
}
if (err.message != null) {
return {
message: err.message,
status: err.status ?? null,
path: err.path ?? null,
method: err.method ?? null,
};
}
return { message: String(err), status: null, path: null, method: null };
}
/** Read structured error from a rejected RTK async thunk action. */
export function resolveBackendError(action) {
if (action.payload) return backendErrorFrom(action.payload);
return backendErrorFrom(action.error);
}
export function formatBackendError(error) {
const normalized = backendErrorFrom(error);
const { message, status, path, method } = normalized;
const statusTitle = status != null ? STATUS_TITLES[status] : null;
const genericTitle =
message && GENERIC_HTTP_TITLES.has(message.trim().toLowerCase())
? statusTitle
: null;
const title = statusTitle || genericTitle || (status != null ? `HTTP ${status}` : 'Backend-Fehler');
const detail =
message &&
message.trim().toLowerCase() !== title?.trim().toLowerCase() &&
!GENERIC_HTTP_TITLES.has(message.trim().toLowerCase())
? message
: null;
const request = path ? `${method || 'GET'} ${path}` : null;
return { title, detail, status, request };
}
export function catchBackendError(rejectWithValue) {
return (err) => rejectWithValue(backendErrorFrom(err));
}
export function isBackendFailure(error) {
const normalized = backendErrorFrom(error);
return normalized.status != null || normalized.path != null;
}