| |
| |
| |
| |
| |
| |
|
|
| const BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000/api/v1"; |
|
|
| export type ApiError = { |
| message: string; |
| status?: number; |
| detail?: any; |
| }; |
|
|
| async function request<T>( |
| endpoint: string, |
| options: RequestInit & { params?: Record<string, string> } = {} |
| ): Promise<T> { |
| const { params, headers: customHeaders, ...config } = options; |
|
|
| |
| const url = new URL(`${BASE_URL}${endpoint}`); |
| if (params) { |
| Object.entries(params).forEach(([key, val]) => url.searchParams.append(key, val)); |
| } |
|
|
| |
| const token = typeof window !== "undefined" ? localStorage.getItem("token") : null; |
|
|
| |
| const headers: Record<string, string> = {}; |
|
|
| |
| const isFormData = config.body instanceof FormData; |
| if (!isFormData) { |
| headers["Content-Type"] = "application/json"; |
| } |
|
|
| |
| if (token) { |
| headers["Authorization"] = `Bearer ${token}`; |
| } |
|
|
| |
| if (customHeaders) { |
| if (customHeaders instanceof Headers) { |
| customHeaders.forEach((value, key) => { |
| headers[key] = value; |
| }); |
| } else if (Array.isArray(customHeaders)) { |
| customHeaders.forEach(([key, value]) => { |
| headers[key] = value; |
| }); |
| } else { |
| Object.assign(headers, customHeaders as Record<string, string>); |
| } |
| } |
|
|
| const finalConfig: RequestInit = { |
| ...config, |
| headers, |
| }; |
|
|
| try { |
| const response = await fetch(url.toString(), finalConfig); |
|
|
| |
| if (response.status === 401) { |
| if (typeof window !== "undefined") { |
| localStorage.removeItem("token"); |
| |
| window.location.href = "/login?error=session_expired"; |
| } |
| throw new Error("Unauthorized access. Please log in again."); |
| } |
|
|
| |
| if (response.status === 204) return {} as T; |
| |
| const data = await response.json(); |
|
|
| if (!response.ok) { |
| |
| const errorMsg = data.detail || "The research server encountered an issue."; |
| return Promise.reject({ message: errorMsg, status: response.status, detail: data }); |
| } |
|
|
| return data as T; |
| } catch (err: any) { |
| |
| return Promise.reject({ |
| message: err.message || "Unable to connect to the research server. Check your connection.", |
| status: err.status || 500 |
| }); |
| } |
| } |
|
|
| export const api = { |
| get: <T>(url: string, p?: Record<string, string>) => request<T>(url, { method: "GET", params: p }), |
| post: <T>(url: string, body: any) => request<T>(url, { method: "POST", body: JSON.stringify(body) }), |
| put: <T>(url: string, body: any) => request<T>(url, { method: "PUT", body: JSON.stringify(body) }), |
| delete: <T>(url: string) => request<T>(url, { method: "DELETE" }), |
| |
| upload: <T>(url: string, formData: FormData) => request<T>(url, { method: "POST", body: formData }), |
| }; |
|
|