1- // Environment validation
1+ import axios , { AxiosInstance , AxiosRequestConfig , AxiosResponse } from 'axios' ;
2+ import Cookies from 'js-cookie' ;
3+
24const API_BASE_URL = process . env . NEXT_PUBLIC_API_BASE_URL ;
35if ( ! API_BASE_URL ) {
46 throw new Error (
57 'NEXT_PUBLIC_API_BASE_URL environment variable is not defined'
68 ) ;
79}
810
9- // Types for API responses
1011export interface ApiResponse < T = unknown > {
1112 data : T ;
1213 status : number ;
@@ -19,110 +20,144 @@ export interface ApiError {
1920 code ?: string ;
2021}
2122
22- // Request configuration interface
2323export interface RequestConfig {
2424 headers ?: Record < string , string > ;
2525 timeout ?: number ;
2626}
2727
28- // Create fetch-based API client
29- const createClientApi = ( ) => {
30- const baseURL = API_BASE_URL ;
31-
32- const createRequestConfig = ( config ?: RequestConfig ) : RequestInit => ( {
33- credentials : 'include' , // Important: enables sending HTTP-only cookies
28+ const createClientApi = ( ) : AxiosInstance => {
29+ const instance = axios . create ( {
30+ baseURL : API_BASE_URL ,
31+ timeout : 10000 ,
3432 headers : {
3533 'Content-Type' : 'application/json' ,
3634 Accept : 'application/json' ,
37- ...config ?. headers ,
3835 } ,
36+ withCredentials : true ,
3937 } ) ;
4038
41- const handleResponse = async < T > (
42- response : Response
43- ) : Promise < ApiResponse < T > > => {
44- if ( ! response . ok ) {
45- const errorData = await response . json ( ) . catch ( ( ) => ( { } ) ) ;
46- throw new Error (
47- errorData . message || `HTTP error! status: ${ response . status } `
48- ) ;
39+ instance . interceptors . request . use (
40+ config => {
41+ config . withCredentials = true ;
42+
43+ const accessToken = Cookies . get ( 'accessToken' ) ;
44+ if ( accessToken && ! config . headers ?. Authorization ) {
45+ config . headers = config . headers || { } ;
46+ config . headers . Authorization = `Bearer ${ accessToken } ` ;
47+ }
48+
49+ return config ;
50+ } ,
51+ error => {
52+ return Promise . reject ( error ) ;
4953 }
54+ ) ;
5055
51- const data = await response . json ( ) ;
52- return {
56+ instance . interceptors . response . use (
57+ ( response : AxiosResponse ) => {
58+ return response ;
59+ } ,
60+ error => {
61+ if ( error . response ) {
62+ const errorData = error . response . data ;
63+ const customError : ApiError = {
64+ message :
65+ errorData ?. message ||
66+ `HTTP error! status: ${ error . response . status } ` ,
67+ status : error . response . status ,
68+ code : errorData ?. code ,
69+ } ;
70+ return Promise . reject ( customError ) ;
71+ } else if ( error . request ) {
72+ return Promise . reject ( new Error ( 'Network error: No response received' ) ) ;
73+ } else {
74+ return Promise . reject ( new Error ( `Request error: ${ error . message } ` ) ) ;
75+ }
76+ }
77+ ) ;
78+
79+ return instance ;
80+ } ;
81+
82+ const axiosInstance = createClientApi ( ) ;
83+
84+ const convertAxiosResponse = < T > (
85+ response : AxiosResponse < T >
86+ ) : ApiResponse < T > => ( {
87+ data : response . data ,
88+ status : response . status ,
89+ statusText : response . statusText ,
90+ } ) ;
91+
92+ const convertRequestConfig = ( config ?: RequestConfig ) : AxiosRequestConfig => ( {
93+ headers : config ?. headers ,
94+ timeout : config ?. timeout ,
95+ withCredentials : true ,
96+ } ) ;
97+
98+ const clientApi = {
99+ get : async < T = unknown > (
100+ url : string ,
101+ config ?: RequestConfig
102+ ) : Promise < ApiResponse < T > > => {
103+ const response = await axiosInstance . get < T > (
104+ url ,
105+ convertRequestConfig ( config )
106+ ) ;
107+ return convertAxiosResponse ( response ) ;
108+ } ,
109+
110+ post : async < T = unknown > (
111+ url : string ,
112+ data ?: unknown ,
113+ config ?: RequestConfig
114+ ) : Promise < ApiResponse < T > > => {
115+ const response = await axiosInstance . post < T > (
116+ url ,
53117 data ,
54- status : response . status ,
55- statusText : response . statusText ,
56- } ;
57- } ;
118+ convertRequestConfig ( config )
119+ ) ;
120+ return convertAxiosResponse ( response ) ;
121+ } ,
58122
59- const makeRequest = async < T > (
123+ put : async < T = unknown > (
60124 url : string ,
61- options : RequestInit & { config ?: RequestConfig } = { }
125+ data ?: unknown ,
126+ config ?: RequestConfig
62127 ) : Promise < ApiResponse < T > > => {
63- const { config, ...requestOptions } = options ;
64- const fullUrl = url . startsWith ( 'http' ) ? url : `${ baseURL } ${ url } ` ;
65-
66- const response = await fetch ( fullUrl , {
67- ...createRequestConfig ( config ) ,
68- ...requestOptions ,
69- } ) ;
70-
71- return handleResponse < T > ( response ) ;
72- } ;
73-
74- return {
75- get : < T = unknown > (
76- url : string ,
77- config ?: RequestConfig
78- ) : Promise < ApiResponse < T > > =>
79- makeRequest < T > ( url , { method : 'GET' , config } ) ,
80-
81- post : < T = unknown > (
82- url : string ,
83- data ?: unknown ,
84- config ?: RequestConfig
85- ) : Promise < ApiResponse < T > > =>
86- makeRequest < T > ( url , {
87- method : 'POST' ,
88- body : data ? JSON . stringify ( data ) : undefined ,
89- config,
90- } ) ,
91-
92- put : < T = unknown > (
93- url : string ,
94- data ?: unknown ,
95- config ?: RequestConfig
96- ) : Promise < ApiResponse < T > > =>
97- makeRequest < T > ( url , {
98- method : 'PUT' ,
99- body : data ? JSON . stringify ( data ) : undefined ,
100- config,
101- } ) ,
102-
103- patch : < T = unknown > (
104- url : string ,
105- data ?: unknown ,
106- config ?: RequestConfig
107- ) : Promise < ApiResponse < T > > =>
108- makeRequest < T > ( url , {
109- method : 'PATCH' ,
110- body : data ? JSON . stringify ( data ) : undefined ,
111- config,
112- } ) ,
113-
114- delete : < T = unknown > (
115- url : string ,
116- config ?: RequestConfig
117- ) : Promise < ApiResponse < T > > =>
118- makeRequest < T > ( url , { method : 'DELETE' , config } ) ,
119- } ;
120- } ;
128+ const response = await axiosInstance . put < T > (
129+ url ,
130+ data ,
131+ convertRequestConfig ( config )
132+ ) ;
133+ return convertAxiosResponse ( response ) ;
134+ } ,
135+
136+ patch : async < T = unknown > (
137+ url : string ,
138+ data ?: unknown ,
139+ config ?: RequestConfig
140+ ) : Promise < ApiResponse < T > > => {
141+ const response = await axiosInstance . patch < T > (
142+ url ,
143+ data ,
144+ convertRequestConfig ( config )
145+ ) ;
146+ return convertAxiosResponse ( response ) ;
147+ } ,
121148
122- // Create and export the client API instance
123- const clientApi = createClientApi ( ) ;
149+ delete : async < T = unknown > (
150+ url : string ,
151+ config ?: RequestConfig
152+ ) : Promise < ApiResponse < T > > => {
153+ const response = await axiosInstance . delete < T > (
154+ url ,
155+ convertRequestConfig ( config )
156+ ) ;
157+ return convertAxiosResponse ( response ) ;
158+ } ,
159+ } ;
124160
125- // Utility functions for common HTTP methods
126161export const api = {
127162 get : < T = unknown > (
128163 url : string ,
0 commit comments