56 lines
1.3 KiB
TypeScript
56 lines
1.3 KiB
TypeScript
import { ApiError, toApiError } from "./errors";
|
||
|
||
const API_BASE_URL = (import.meta.env.VITE_API_BASE_URL as string | undefined)?.trim() || "http://localhost:3001";
|
||
|
||
function buildUrl(path: string): string {
|
||
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
||
return `${API_BASE_URL}${normalizedPath}`;
|
||
}
|
||
|
||
async function parseResponseBody(response: Response): Promise<unknown> {
|
||
const contentType = response.headers.get("content-type") ?? "";
|
||
if (!contentType.includes("application/json")) {
|
||
return null;
|
||
}
|
||
|
||
try {
|
||
return await response.json();
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export async function requestJson<T>(path: string, init?: RequestInit): Promise<T> {
|
||
try {
|
||
const response = await fetch(buildUrl(path), {
|
||
...init,
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
...(init?.headers ?? {}),
|
||
},
|
||
});
|
||
|
||
if (response.status === 204) {
|
||
return undefined as T;
|
||
}
|
||
|
||
const payload = await parseResponseBody(response);
|
||
|
||
if (!response.ok) {
|
||
throw toApiError(response.status, payload);
|
||
}
|
||
|
||
return payload as T;
|
||
} catch (error) {
|
||
if (error instanceof ApiError) {
|
||
throw error;
|
||
}
|
||
|
||
throw new ApiError({
|
||
code: "network_error",
|
||
status: null,
|
||
message: "Не удалось связаться с сервером.",
|
||
});
|
||
}
|
||
}
|