65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import { clearToken, getToken } from '@/lib/auth'
|
|
|
|
export class ApiError extends Error {
|
|
status: number
|
|
code: string
|
|
|
|
constructor(status: number, code: string, message: string) {
|
|
super(message)
|
|
this.status = status
|
|
this.code = code
|
|
}
|
|
}
|
|
|
|
async function request<T>(
|
|
method: string,
|
|
path: string,
|
|
body?: unknown,
|
|
): Promise<T> {
|
|
const headers: Record<string, string> = {
|
|
Accept: 'application/json',
|
|
}
|
|
const token = getToken()
|
|
if (token) headers.Authorization = `Bearer ${token}`
|
|
if (body !== undefined) headers['Content-Type'] = 'application/json'
|
|
|
|
const res = await fetch(path, {
|
|
method,
|
|
headers,
|
|
credentials: 'include',
|
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
})
|
|
|
|
if (res.status === 204) return undefined as T
|
|
|
|
const text = await res.text()
|
|
let data: unknown = null
|
|
if (text) {
|
|
try {
|
|
data = JSON.parse(text)
|
|
} catch {
|
|
data = { error: { code: 'PARSE_ERROR', message: text } }
|
|
}
|
|
}
|
|
|
|
if (!res.ok) {
|
|
if (res.status === 401) clearToken()
|
|
const err = data as { error?: { code?: string; message?: string } } | null
|
|
throw new ApiError(
|
|
res.status,
|
|
err?.error?.code ?? 'ERROR',
|
|
err?.error?.message ?? res.statusText,
|
|
)
|
|
}
|
|
|
|
return data as T
|
|
}
|
|
|
|
export const api = {
|
|
get: <T>(path: string) => request<T>('GET', path),
|
|
post: <T>(path: string, body?: unknown) => request<T>('POST', path, body),
|
|
patch: <T>(path: string, body?: unknown) => request<T>('PATCH', path, body),
|
|
put: <T>(path: string, body?: unknown) => request<T>('PUT', path, body),
|
|
delete: <T>(path: string) => request<T>('DELETE', path),
|
|
}
|