Download Frontend/lib/api.ts from 0xarchit/CityTrack: direct link, hf CLI and curl.
- Browser
- Download file 3.2 kB
-
https://huggingface.co/spaces/0xarchit/CityTrack/resolve/main/Frontend/lib/api.ts
- Command line
-
hf download hf://spaces/0xarchit/CityTrack/Frontend/lib/api.ts
-
curl -L -o api.ts https://huggingface.co/spaces/0xarchit/CityTrack/resolve/main/Frontend/lib/api.ts
3.2 kB
| "use client"; | |
| const API_URL = process.env.NEXT_PUBLIC_API_URL || ""; | |
| const REQUEST_TIMEOUT_MS = 35000; | |
| const MAX_RETRIES = 3; | |
| class ApiError extends Error { | |
| status: number; | |
| constructor(message: string, status: number) { | |
| super(message); | |
| this.status = status; | |
| this.name = "ApiError"; | |
| } | |
| } | |
| async function fetchWithTimeout( | |
| url: string, | |
| options: RequestInit, | |
| timeout: number, | |
| ): Promise<Response> { | |
| const controller = new AbortController(); | |
| const timeoutId = setTimeout(() => controller.abort(), timeout); | |
| try { | |
| const response = await fetch(url, { | |
| ...options, | |
| signal: controller.signal, | |
| }); | |
| return response; | |
| } finally { | |
| clearTimeout(timeoutId); | |
| } | |
| } | |
| export async function apiRequest<T>( | |
| endpoint: string, | |
| options: RequestInit = {}, | |
| retries = 0, | |
| ): Promise<T> { | |
| const token = | |
| typeof window !== "undefined" ? localStorage.getItem("token") : null; | |
| if (!API_URL) { | |
| throw new ApiError("API URL not configured", 500); | |
| } | |
| const headers: HeadersInit = { | |
| "Content-Type": "application/json", | |
| ...(token ? { Authorization: `Bearer ${token}` } : {}), | |
| ...options.headers, | |
| }; | |
| try { | |
| const res = await fetchWithTimeout( | |
| `${API_URL}${endpoint}`, | |
| { ...options, headers }, | |
| REQUEST_TIMEOUT_MS, | |
| ); | |
| if (res.status === 401 || res.status === 403) { | |
| if (typeof window !== "undefined") { | |
| localStorage.removeItem("token"); | |
| localStorage.removeItem("user"); | |
| window.location.href = "/signin"; | |
| } | |
| throw new ApiError("Session expired. Please sign in again.", res.status); | |
| } | |
| if (res.status >= 500 && retries < MAX_RETRIES) { | |
| await new Promise((r) => setTimeout(r, 1000 * (retries + 1))); | |
| return apiRequest<T>(endpoint, options, retries + 1); | |
| } | |
| if (!res.ok) { | |
| const data = await res.json().catch(() => ({})); | |
| throw new ApiError(data.detail || "Request failed", res.status); | |
| } | |
| if (res.status === 204) { | |
| return {} as T; | |
| } | |
| return res.json(); | |
| } catch (error) { | |
| if (error instanceof ApiError) throw error; | |
| if (error instanceof Error) { | |
| if (error.name === "AbortError") { | |
| throw new ApiError("Request timed out. Please try again.", 408); | |
| } | |
| if (retries < MAX_RETRIES) { | |
| await new Promise((r) => setTimeout(r, 1000 * (retries + 1))); | |
| return apiRequest<T>(endpoint, options, retries + 1); | |
| } | |
| } | |
| throw new ApiError("Network error. Please check your connection.", 0); | |
| } | |
| } | |
| export async function apiGet<T>(endpoint: string): Promise<T> { | |
| return apiRequest<T>(endpoint, { method: "GET" }); | |
| } | |
| export async function apiPost<T>(endpoint: string, body?: unknown): Promise<T> { | |
| return apiRequest<T>(endpoint, { | |
| method: "POST", | |
| body: body ? JSON.stringify(body) : undefined, | |
| }); | |
| } | |
| export async function apiPatch<T>( | |
| endpoint: string, | |
| body?: unknown, | |
| ): Promise<T> { | |
| return apiRequest<T>(endpoint, { | |
| method: "PATCH", | |
| body: body ? JSON.stringify(body) : undefined, | |
| }); | |
| } | |
| export async function apiDelete(endpoint: string): Promise<void> { | |
| await apiRequest(endpoint, { method: "DELETE" }); | |
| } | |
| export { ApiError }; | |