Files
nuzlocke-tracker/frontend/src/api/client.ts
Julian Tabel 55e6650e0e Add admin panel with CRUD endpoints and management UI
Add admin API endpoints for games, routes, pokemon, and route encounters
with full CRUD operations including bulk import. Build admin frontend
with game/route/pokemon management pages, navigation, and data tables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:36:19 +01:00

58 lines
1.2 KiB
TypeScript

const API_BASE = import.meta.env.VITE_API_URL ?? ''
export class ApiError extends Error {
status: number
constructor(status: number, message: string) {
super(message)
this.name = 'ApiError'
this.status = status
}
}
async function request<T>(
path: string,
options?: RequestInit,
): Promise<T> {
const res = await fetch(`${API_BASE}/api/v1${path}`, {
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
})
if (!res.ok) {
const body = await res.json().catch(() => ({}))
throw new ApiError(res.status, body.detail ?? res.statusText)
}
if (res.status === 204) return undefined as T
return res.json()
}
export const api = {
get: <T>(path: string) => request<T>(path),
post: <T>(path: string, body: unknown) =>
request<T>(path, {
method: 'POST',
body: JSON.stringify(body),
}),
patch: <T>(path: string, body: unknown) =>
request<T>(path, {
method: 'PATCH',
body: JSON.stringify(body),
}),
put: <T>(path: string, body: unknown) =>
request<T>(path, {
method: 'PUT',
body: JSON.stringify(body),
}),
del: <T = void>(path: string) =>
request<T>(path, { method: 'DELETE' }),
}