57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
import type { ApiResult, HealthResponse, SessionDetailResponse } from './types';
|
|
|
|
export interface ApiClient {
|
|
health(): Promise<ApiResult<HealthResponse>>;
|
|
getSession(code: string): Promise<ApiResult<SessionDetailResponse>>;
|
|
}
|
|
|
|
export function createApiClient(baseUrl = '', fetchImpl: typeof fetch = fetch): ApiClient {
|
|
async function request<T>(path: string): Promise<ApiResult<T>> {
|
|
let response: Response;
|
|
try {
|
|
response = await fetchImpl(`${baseUrl}${path}`, {
|
|
method: 'GET',
|
|
headers: { Accept: 'application/json' }
|
|
});
|
|
} catch {
|
|
return {
|
|
ok: false,
|
|
status: 0,
|
|
error: { kind: 'network', status: 0, message: 'Network error while contacting API' }
|
|
};
|
|
}
|
|
|
|
let payload: unknown;
|
|
try {
|
|
payload = await response.json();
|
|
} catch {
|
|
return {
|
|
ok: false,
|
|
status: response.status,
|
|
error: { kind: 'parse', status: response.status, message: 'Invalid JSON response from API' }
|
|
};
|
|
}
|
|
|
|
if (!response.ok) {
|
|
return {
|
|
ok: false,
|
|
status: response.status,
|
|
error: {
|
|
kind: 'http',
|
|
status: response.status,
|
|
message: `HTTP ${response.status}`,
|
|
payload
|
|
}
|
|
};
|
|
}
|
|
|
|
return { ok: true, status: response.status, data: payload as T };
|
|
}
|
|
|
|
return {
|
|
health: () => request<HealthResponse>('/healthz'),
|
|
getSession: (code: string) =>
|
|
request<SessionDetailResponse>(`/lobby/sessions/${encodeURIComponent(code.trim().toUpperCase())}`)
|
|
};
|
|
}
|