spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1'use client';2import type { DNAResponse, SearchResponse, SeriesResponse, SimilarResponse } from './types';34/**5 * Browser-side fetch helpers: same-origin `/api/v1/*` (rewritten by next.config.ts to the FastAPI service).6 * Kept deliberately small — server components should do the heavy lifting.7 */8export class ClientApiError extends Error {9 constructor(10 readonly status: number,11 message: string,12 ) {13 super(message);14 this.name = 'ClientApiError';15 }16}1718async function get<T>(path: string, signal?: AbortSignal): Promise<T> {19 const res = await fetch(`/api/v1${path}`, { headers: { accept: 'application/json' }, signal });20 if (!res.ok) throw new ClientApiError(res.status, `API ${res.status}`);21 return (await res.json()) as T;22}2324export const clientApi = {25 search: (q: string, limit = 12, signal?: AbortSignal) =>26 get<SearchResponse>(`/search?q=${encodeURIComponent(q)}&limit=${limit}`, signal),27 countrySeries: (id: string, indicator: string, signal?: AbortSignal) =>28 get<SeriesResponse>(`/countries/${encodeURIComponent(id)}/series/${encodeURIComponent(indicator)}`, signal),29 countrySimilar: (id: string, mode: string, signal?: AbortSignal) =>30 get<SimilarResponse>(`/countries/${encodeURIComponent(id)}/similar?mode=${encodeURIComponent(mode)}`, signal),31 countryDna: (id: string, reference: string, signal?: AbortSignal) =>32 get<DNAResponse>(`/countries/${encodeURIComponent(id)}/dna?reference=${encodeURIComponent(reference)}`, signal),33};34