57 lines
1.6 KiB
TypeScript
57 lines
1.6 KiB
TypeScript
|
|
import { API_URL } from '../config';
|
||
|
|
|
||
|
|
/** Errore restituito dal server nella forma { error: { code, message } }. */
|
||
|
|
export class ApiError extends Error {
|
||
|
|
constructor(
|
||
|
|
public readonly status: number,
|
||
|
|
public readonly code: string,
|
||
|
|
message: string,
|
||
|
|
) {
|
||
|
|
super(message);
|
||
|
|
this.name = 'ApiError';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
let accessToken: string | null = null;
|
||
|
|
|
||
|
|
export function setAccessToken(token: string | null): void {
|
||
|
|
accessToken = token;
|
||
|
|
}
|
||
|
|
|
||
|
|
type RequestOptions = {
|
||
|
|
method?: 'GET' | 'POST';
|
||
|
|
body?: unknown;
|
||
|
|
};
|
||
|
|
|
||
|
|
export async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
|
||
|
|
const headers: Record<string, string> = {};
|
||
|
|
if (options.body !== undefined) headers['Content-Type'] = 'application/json';
|
||
|
|
if (accessToken) headers['Authorization'] = `Bearer ${accessToken}`;
|
||
|
|
|
||
|
|
let response: Response;
|
||
|
|
try {
|
||
|
|
response = await fetch(`${API_URL}/api/v1${path}`, {
|
||
|
|
method: options.method ?? 'GET',
|
||
|
|
headers,
|
||
|
|
body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
|
||
|
|
});
|
||
|
|
} catch {
|
||
|
|
throw new ApiError(0, 'NETWORK_ERROR', 'Server non raggiungibile');
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
let code = 'REQUEST_ERROR';
|
||
|
|
let message = `Errore ${response.status}`;
|
||
|
|
try {
|
||
|
|
const payload = (await response.json()) as { error?: { code?: string; message?: string } };
|
||
|
|
code = payload.error?.code ?? code;
|
||
|
|
message = payload.error?.message ?? message;
|
||
|
|
} catch {
|
||
|
|
// risposta non JSON: si tengono i default
|
||
|
|
}
|
||
|
|
throw new ApiError(response.status, code, message);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (await response.json()) as T;
|
||
|
|
}
|