import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; import { getAccessTokenCookie } from "@utils/auth"; const axiosInstance: AxiosInstance = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL, }); export enum APIPath { TAGS = "/tags/:id", EVENTS = "/events/:id", FEED = "/feed/:id", JOBADS = "/jobads/:id", SIGNUPS = "/signup/:id", SIGNUPS_EDIT = "/signup/:id/edit", SIGNUP_FORMS = "/signupForm/:id", SIGNUP_FORMS_EMAIL = "/signupForm/:id/sendemail", SIGNUP_FORMS_SIGNUPS = "/signupForm/:id/signups", AUTH_TOKEN_GENERATE = "/token", AUTH_TOKEN_VERIFY = "/token/verify", AUTH_TOKEN_REFRESH = "/token/refresh", } export type API = { path: APIPath; urlParams?: { id?: string | number; }; queryParams?: { limit?: number; offset?: number; since?: Date; uuid?: string; }; authenticated?: boolean; }; type Headers = { Authorization?: string; }; const getAuthHeader = (): string => { const jwt = getAccessTokenCookie(); return `Bearer ${jwt}`; }; const getHeaders = (auth?: boolean): Headers => { if (auth) { return { Authorization: getAuthHeader(), }; } return {}; }; const fillUrlParams = (apiPath: APIPath, params: API["urlParams"] = {}): string => { const path = apiPath .split("/") .map((urlComponent) => { // fill in each placeholder component like ':id' with value from params if (urlComponent.startsWith(":")) { const key = urlComponent.substring(1); const value = params[key] ?? ""; return value; } return urlComponent; }) .filter(Boolean) .join("/"); // code above strips leading and trailing '/' from path return `/${path}/`; }; const callBackendAPI = async ( path: APIPath, urlParams: API["urlParams"], queryParams: API["queryParams"], method: AxiosRequestConfig["method"], headers: Headers, requestBody: RequestType, ): Promise => { const url = fillUrlParams(path, urlParams); const request: AxiosRequestConfig = { url, method, headers, params: queryParams, data: requestBody, responseType: "json", }; const response = await axiosInstance.request(request); const arrayResp = (response.data as { results?: ResponseType }); if (Array.isArray(arrayResp.results)) { return arrayResp.results; } return response.data; }; export const getBackendAPI = async ({ path, urlParams, queryParams, authenticated, }: API): Promise => { const headers = getHeaders(authenticated); return callBackendAPI(path, urlParams, queryParams, "GET", headers, undefined); }; export const postBackendAPI = async ({ path, urlParams, queryParams, authenticated, }: API, body: RequestType): Promise => { const headers = getHeaders(authenticated); return callBackendAPI(path, urlParams, queryParams, "POST", headers, body); }; export const putBackendAPI = async ({ path, urlParams, queryParams, authenticated, }: API, body: RequestType): Promise => { const headers = getHeaders(authenticated); return callBackendAPI(path, urlParams, queryParams, "PUT", headers, body); }; export const deleteBackendAPI = async ({ path, urlParams, queryParams, authenticated, }: API): Promise => { const headers = getHeaders(authenticated); return callBackendAPI(path, urlParams, queryParams, "DELETE", headers, undefined); }; export const fetcher = ({ path, urlParams, queryParams, authenticated, }: API) => getBackendAPI({ path, urlParams, queryParams, authenticated, });