Axios middleware to use in all instances of axios
As per the documentation - You need to create a file i.e
// api-client.jsimport axios from 'axios';// Add a request interceptoraxios.interceptors.request.use(function (config) { // Do something before request is sent console.log(config); return config; }, function (error) { // Do something with request error return Promise.reject(error); });// Add a response interceptoraxios.interceptors.response.use(function (response) { // Do something with response data return response; }, function (error) { // Do something with response error return Promise.reject(error); });export default axios;
Then from your container or controller, import above file:
// Home.jsimport apiClient from './api-client.js';
Interceptors are the Axios way of doing this. For me though, it was too limited, tangled in Axios' API, difficult to test, etc.
Axios-middleware
So I wrote the axios-middleware module, a simple middleware service that hooks itself in your axios instance (either global or a local one) and provides a simple, self-contained and easily testable middleware API.
Note: it shines in bigger apps where minimal coupling is really important.
Simple example
Here's a simple example from the documentation
import axios from 'axios';import { Service } from 'axios-middleware';const service = new Service(axios);service.register({ onRequest(config) { console.log('onRequest'); return config; }, onSync(promise) { console.log('onSync'); return promise; }, onResponse(response) { console.log('onResponse'); return response; }});console.log('Ready to fetch.');// Just use axios like you would normally.axios('https://jsonplaceholder.typicode.com/posts/1') .then(({ data }) => console.log('Received:', data));
It should output:
Ready to fetch.onRequestonSynconResponseReceived: {userId: 1, id: 1, title: ...
Testing a middleware
Say we have the following self-contained middleware class that we want to test.
export default class ApiErrorMiddleware { constructor(toast) { this.toast = toast; } onResponseError(err = {}) { let errorKey = 'errors.default'; const { response } = err; if (response && response.status) { errorKey = `errors.${response.status}`; } else if (err.message === 'Network Error') { errorKey = 'errors.network-error'; } this.toast.error(errorKey); throw err; }}
Then it's really easy, we don't even need to mock Axios.
import ApiErrorMiddleware from '@/middlewares/ApiErrorMiddleware';describe('ApiErrorMiddleware', () => { let toast; let middleware; // Jest needs a function when we're expecting an error to be thrown. function onResponseError(err) { return () => middleware.onResponseError(err); } beforeEach(() => { toast = { error: jest.fn() }; middleware = new ApiErrorMiddleware(toast); }); it('sends a code error message', () => { hasKey = true; expect(onResponseError({ response: { status: 404 } })).toThrow(); expect(toast.error).toHaveBeenLastCalledWith('errors.404'); });});