Axios Global Interceptor Config
Interceptor Config
- create a new file with the name
axios.ts
- add the validation for api url from environmentConstants
import { apiBaseUrl } from "../constants/environmentConstants";
if (!apiBaseUrl) {
throw new Error("No Api apiBaseUrl");
}
- import axios from axios and add header for post request
axios.defaults.headers.post["Content-Type"] = "application/json";
- create a function
createApi
that takes a path and returns an axios instance
export default const createApi = (path: string) => {
const api = axios.create({
baseURL: `${apiBaseUrl}${path}`,
timeout: 10000,
headers: {
"Content-Type": "application/json",
},
});
return api;
};
- add the interceptor for request and responses
export default const createApi = (path: string) => {
// ...
api.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
// get session from next-auth
const session = await getSession();
// set the access token in the header for every request after logged in
if (session?.accessToken) {
config.headers.set("Authorization", `Bearer ${session.accessToken}`);
}
return config;
});
api.interceptors.response.use(
null,
(error: AxiosError<{ statusCode: string | number; message: string }>) => {
// handle different global error types
if (error.message === "Network Error"){
//handle network error
return;
}
if (Number(error.response?.status) >= 500) {
//handle 500 error
return;
}
if (
Number(error.response?.data?.statusCode) === 403 &&
error.response?.data?.message === "Invalid User Status"
) {
// handle 403 error
return;
}
// return non global error for manual handling
throw error;
},
);
- example for
axios.ts
file will look like this
import axios, { AxiosError, InternalAxiosRequestConfig } from "axios";
import { getSession, signOut } from "next-auth/react";
import { enqueueSnackbar } from "notistack";
import { apiBaseUrl } from "../constants/environmentConstants";
if (!apiBaseUrl) {
throw new Error("No Api apiBaseUrl");
}
axios.defaults.headers.post["Content-Type"] = "application/json";
export default const createApi = (path: string) => {
const api = axios.create({
baseURL: `${apiBaseUrl}${path}`,
timeout: 10000,
headers: {
"Content-Type": "application/json",
},
});
api.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
const session = await getSession();
if (session?.accessToken) {
config.headers.set("Authorization", `Bearer ${session.accessToken}`);
}
return config;
});
api.interceptors.response.use(
null,
(error: AxiosError<{ statusCode: string | number; message: string }>) => {
if (error.message === "Network Error")
return enqueueSnackbar("Slow Internet", { variant: "error" });
if (Number(error.response?.status) >= 500) {
enqueueSnackbar("Error", { variant: "error" });
return;
}
if (
Number(error.response?.data?.statusCode) === 403 &&
error.response?.data?.message === "Invalid User Status"
) {
return signOut({ callbackUrl: "/" });
}
throw error;
},
);
return api;
};
Using the axios interceptor for requests
// ... other imports
import { METHODS } from '../enums'; // enums that have all the methods
import createApi from '../utils/axios';
const requestApi = createApi("/url");
export const apiFunctionName = async ({
params,
requestData
}: {
requestData: IRequestType
params: IParamType;
}): Promise<IResponseType>> => {
const { data } = await requestApi({
url: '/extendedUrl',
method: METHODS.GET, // or POST, PATCH and DELETE
daya: requestData,
params,
});
return data;
};
Conclusion
This is a global axios interceptor that handles requests and responses. It is a good practice to handle global errors in one place and not repeat the same code in every request.