frontend_nyla/src/hooks/useApi.ts

78 lines
No EOL
2.2 KiB
TypeScript

import { useState, useCallback } from 'react';
import api from '../api';
// Generic API error handling
export function formatApiError(error: any, defaultMessage: string): string {
if (error.response) {
const data = error.response.data;
// Handle FastAPI validation errors (detail is an array)
if (data?.detail && Array.isArray(data.detail)) {
return data.detail.map((err: any) => {
if (typeof err === 'string') return err;
if (err.msg) return `${err.loc?.join('.') || 'field'}: ${err.msg}`;
return JSON.stringify(err);
}).join(', ');
}
// Handle other error formats
if (typeof data?.detail === 'string') return data.detail;
if (typeof data?.message === 'string') return data.message;
if (typeof data === 'string') return data;
return defaultMessage;
} else if (error.request) {
return 'Keine Antwort vom Server erhalten';
} else {
return error.message || defaultMessage;
}
}
// Type for API request options
export interface ApiRequestOptions<T> {
url: string;
method: 'get' | 'post' | 'put' | 'delete';
data?: T;
params?: Record<string, string | number | boolean>;
additionalConfig?: Record<string, any>; // For responseType, headers, etc.
}
// Hook for making API requests with consistent error handling
export function useApiRequest<RequestData = any, ResponseData = any>() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const request = useCallback(async ({
url,
method,
data,
params,
additionalConfig = {}
}: ApiRequestOptions<RequestData>): Promise<ResponseData> => {
setIsLoading(true);
setError(null);
try {
const response = await api({
url,
method,
data,
params,
...additionalConfig
});
return response.data;
} catch (error: any) {
const errorMessage = formatApiError(error, `Fehler bei ${method.toUpperCase()} ${url}`);
setError(errorMessage);
throw new Error(String(errorMessage)); // Ensure it's a string
} finally {
setIsLoading(false);
}
}, []);
return {
request,
isLoading,
error
};
}