Refactor your code with axios.interceptors()

Introduction

When you request the data from the server, we use the default fetch(). However, after the powerful ajax method $http emerged with Angular, there is enormous demand for $http like Ajax library for a non-angular framework. So, it is axios: the reason why people use it.
In this post, I introduce the way I use with axios, and how I refactor those with axios.interceptors()

How I handle axios API before

My major concept of handling axios API is Ajax should be moduled separately and only triggered by related solitary action modules. e.g. global actions for module reducers of Redux or Vuex.

Check out the example code for ajax with axios API. This is just a simple logical code, you can convert and apply to your framework as well.

Example Code

  1. .env is the environment module. APP_URI declared in it.
.env
APP_URI=https://jsonplaceholder.typicode.com
  1. Assume that API module in api variable. trying to get some comments by Ajax request to API(Using https://jsonplaceholder.typicode.com). if it gets an error, it consoles the error and throws it to the upper caller.
API Module
export const api = {
	async getComments(postId) {
		const headers = { 'X-Requested-With': 'XMLHttpRequest' };
		const API = `${process.env.APP_URI}/comments?postId=${postId}`;

		try {
			const res = await axios({ method: 'GET', url: API, headers });
			const { data } = res;

			const emailList = data.map((post) => post.email);

			return emailList;
		} catch (error) {
			console.error(error.message);
			throw error;
		}
	},
};
  1. this getComments() from API module is triggered from the global action module. Assume actions variable is the global action module. It manipulate the data from here. Same as api modules, it throws an error to the upper caller.
Global Actions
import api from '@/api';

export const actions = {
	async updateEmailAction({ commit }, id) {
		try {
			const emails = await api.getComments(id);

			commit('updateEmail', emails);
		} catch (error) {
			console.error(error.message);
			throw error;
		}
	},
};
  1. lastly, getEmails() from the component triggers the updateEmailAction() from actions=> modules. If it pass all the procedure, pops up the message about complete. If it takes an error from the updateEmailAction(), it pops up the error message.
Component
import actions from '@/store/actions';

const getEmails = async () => {
	try {
		await actions.updateEmailAction();
		alert('complete: email loading!');
	} catch (error) {
		alert(error.message);
	}
};
  1. Here is all the legacy code explained above.
Overall
// @ .env
// APP_URI=https://jsonplaceholder.typicode.com

// @ API module
export const api = {
	async getComments(postId) {
		const headers = { 'X-Requested-With': 'XMLHttpRequest' };
		const API = `${process.env.APP_URI}/comments?postId=${postId}`;

		try {
			const res = await axios({ method: 'GET', url: API, headers });
			const { data } = res;

			const emailList = data.map((post) => post.email);

			return emailList;
		} catch (error) {
			console.error(error.message);
			throw error;
		}
	},
};

// @ global action
import api from '@/api';

export const actions = {
	async updateEmailAction({ commit }, id) {
		try {
			const emails = await api.getComments(id);

			commit('updateEmail', emails);
		} catch (error) {
			console.error(error.message);
			throw error;
		}
	},
};

// @ component
import actions from '@/store/actions';

const getEmails = async () => {
	try {
		await actions.updateEmailAction();
		alert('complete: email loading!');
	} catch (error) {
		alert(error.message);
	}
};

axios.interceptors.request & axios.interceptors.response

axios has intercept method called interceptors(). more specifically, there are two main interceptor methods: request and response.
Basically, interceptors method hijacks the connection before ajax catches, so you can manipulate or add some actions to every axios request and response.

So, this is an example that I refactored the axios code with axios.interceptors

  1. At first, define a common key or code for request and response for Ajax. Go to the main script and apply those common scripts by using axios.interceptors request and response. In this example, if it gets an error from a response or request, it consoles the error message, so that you can reduce additional console error message lines for each axios api.
Main
axios.interceptors.request.use(
	(config) => {
		config.headers['X-Requested-With'] = 'XMLHttpRequest';
		return config;
	},
	(error) => {
		console.error(error.response.data.message);
		return Promise.reject(error.response.data);
	}
);

axios.interceptors.response.use(
	(response) => {
		return response;
	},
	(error) => {
		console.error(error.response.data.message);
		return Promise.reject(error.response.data);
	}
);
  1. Now, api code is dramatically reduced. you don’t have to manipulate data from response here, but able to do in global actions. It means you don’t have to try...catch here, but only return async response. Plus, headers is the default value for the axios request because it is already coded in the main script. Therefore, you need only axios.get(API).
    URLSearchParams() is a more efficient way to control params for URI than adding (+=) the param text to the end. (Already posted another article about URLSearchParams()LINK .)
API Module
export const api = {
	async getComments(postId) {
		const params = new URLSearchParams({
			postId,
		});
		const API = `${process.env.APP_URI}/comments?${params.toString()}`;
		return await axios.get(API);
	},
};
  1. In the global actions module, manipulate the response data. others are all the same as above except disappeared console error message. Here is all the refactored code explained above.
// @ .env
// APP_URI=https://jsonplaceholder.typicode.com

// @ main
axios.interceptors.request.use(
	(config) => {
		config.headers['X-Requested-With'] = 'XMLHttpRequest';
		return config;
	},
	(error) => {
		console.error(error.response.data.message);
		return Promise.reject(error.response.data);
	}
);

axios.interceptors.response.use(
	(response) => {
		return response;
	},
	(error) => {
		console.error(error.response.data.message);
		return Promise.reject(error.response.data);
	}
);

// @ API module
export const api = {
	async getComments(postId) {
		const params = new URLSearchParams({
			postId,
		});
		const API = `${process.env.APP_URI}/comments?${params.toString()}`;
		return await axios.get(API);
	},
};

// @ global action
import api from '@/api';

export const actions = {
	async updateEmailAction({ commit }, id) {
		try {
			const { data } = await api.getComments(id);
			const emailList = data.map((post) => post.email);
			commit('updateEmail', emailList);
		} catch (error) {
			throw error;
		}
	},
};

// @ component
import actions from '@/store/actions';

const getEmails = async () => {
	try {
		await actions.updateEmailAction();
		alert('complete: email loading!');
	} catch (error) {
		alert(error.message);
	}
};

Conclusion

That’s it!
Always consider better and minify the code! If you are React or Vue user, I guess you are Axios users, too. If the service gets larger and larger, the endpoint will increase more and more. In this situation, axios.interceptors will be your essential refactor work for all your project.