axios
is a really cool http client library for building a Web Application these days, but how can you customize the config so that you can determine the behavior of a request dynamically based on a property when you want to hit an endpoint of your API?
Let's say we have an instance of axios that we configure the base URL so that every time we want to hit our API, we just need to specify the path of the url.
// src/http.js
import axios from 'axios';
const http = axios.create({
baseURL: 'https://api.your-project.com',
});
export default http;
And then we have an interceptor to show a toast error message when we receive error response from our API:
// src/http.js
import axios from 'axios';
import { toast } from 'react-toastify';
const http = axios.create({
baseURL: 'https://api.your-project.com',
});
http.interceptors.response.use(
response => response,
error => {
let message = 'Unknown Error';
if (axios.isAxiosError(error)) {
message = error.response?.data.error || error.response?.data.message;
}
if (error instanceof TypeError) {
message = error.message;
}
toast.error(message);
return Promise.reject(error);
},
);
export default http;
Now if we want to add additional config to tell our interceptor that we don't want to show error message, we can do this:
// src/clients/users.js
import { http } from '@app/http';
export const getUserProfile = () => {
return http.request({
method: 'GET',
url: '/user/profile',
disableToast: true,
});
};
Then what we need to do is to modify our interceptor to respect with that property:
// src/http.js
http.interceptors.response.use(
response => response,
error => {
let message = 'Unknown Error';
if (axios.isAxiosError(error)) {
message = error.response?.data.error || error.response?.data.message;
}
if (error instanceof TypeError) {
message = error.message;
}
if (!error.config.disableToast) {
toast.error(message);
}
return Promise.reject(error);
},
);
TypeScript
If you're using TypeScript, then you will notice that in src/clients/user.js
, we're not allowed to call axios.request
with disableToast
property. And the same error goes to our interceptor, it will look something like this.
Property 'disableToast' does not exist on type
AxiosRequestConfig<any>
.(2339)
To solve this, we need to tell TypeScript that disableToast
is actually exist on the AxiosRequestConfig
type.
// src/@types/axios.d.ts
import 'axios';
declare module 'axios' {
export interface AxiosRequestConfig {
disableToast?: boolean;
}
}
In above snippet we're creating a new declaration file and extends the existing interface from axios. But you can also solve this problem by inlining the declaration like this.
This is called Declaration Merging, you can read more about them here. But in short, we are adding another property to the AxiosRequestConfig
interface from axios
.