forked from StellarTickets/frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.ts
More file actions
59 lines (49 loc) · 1.65 KB
/
Copy pathapi.ts
File metadata and controls
59 lines (49 loc) · 1.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:3000';
const TOKEN_KEY = 'stellartickets.token';
export class ApiError extends Error {
constructor(
message: string,
public readonly status: number,
) {
super(message);
this.name = 'ApiError';
}
}
export function getToken(): string | null {
if (typeof window === 'undefined') return null;
return window.localStorage.getItem(TOKEN_KEY);
}
export function setToken(token: string) {
window.localStorage.setItem(TOKEN_KEY, token);
}
export function clearToken() {
window.localStorage.removeItem(TOKEN_KEY);
}
interface RequestOptions {
method?: 'GET' | 'POST' | 'PATCH' | 'DELETE';
body?: unknown;
auth?: boolean;
}
/** Backend BigInt fields (prices, chain ids) arrive as JSON strings/numbers depending on Nest's serializer; kept as strings end-to-end. */
export async function apiFetch<T>(path: string, options: RequestOptions = {}): Promise<T> {
const { method = 'GET', body, auth = true } = options;
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
if (auth) {
const token = getToken();
if (token) headers.Authorization = `Bearer ${token}`;
}
const res = await fetch(`${API_URL}${path}`, {
method,
headers,
body: body !== undefined ? JSON.stringify(body) : undefined,
});
if (!res.ok) {
const payload = await res.json().catch(() => null);
const message = Array.isArray(payload?.message)
? payload.message.join(', ')
: (payload?.message ?? res.statusText);
throw new ApiError(message, res.status);
}
if (res.status === 204) return undefined as T;
return res.json() as Promise<T>;
}