npm install axios and import it: import axios from "axios";.
Create a Promise object using axios.get, axios.post, etc.
Chain .then() and .catch() for handling response and error respectively.
Adding Interceptors
It's very common to handle errors and HTTP requests locally within a component. For example, a component may have a this.state.error to track if something breaks during a .catch(). Then, the UI will render a message to the user if this.state.error has content.
However, on top of local HTTP request and error handling, you can use interceptors that add global customization to your HTTP requests and errors.
Think of interceptors as middle men that are passed the request, response, or error object to do custom work. Then you pass the objects forward for local handling.
// In a global file like index.js, add this...
// ** FOR REQUESTS **
const reqInterceptor = axios.interceptors.request.use(request => {
// Do something before request is sent
// COMMON PRACTICE: Add authorization headers
return request; // pushes forward request for local handling
}, error => {
// Do something with error
return Promise.reject(error); // pushes forwards error for local handling
});
// ** FOR RESPONSES **
const resInterceptor = axios.interceptors.response.use(response => {
// Do something with response data
return response; // pushes forward response for local handling
}, error => {
// Do something with error
return Promise.reject(error); // pushes forwards error for local handling
});
Note: It's a good idea to add eject as part of a cleanup function like componentWillUnmount or the cleanup callback in useEffect.
Global Configuration
axios and other request libraries give you access to a defaults object for configuring defaults.
// In a global file like index.js...
axios.defaults.baseURL = "https://api.com/v1"; // Base URL for API endpoint
axios.defaults.headers.common // For headers that apply to all requests
axios.defaults.headers.post // For headers specifically for POST requests
Axios Instances
Sometimes your axios configuration needs to be different for different situations. For this, you can set up half measures known as an instance.
import axios from "axios";
const axiosInstance = axios.create({
baseURL: "https://api.com/v2"
});
// axiosInstance.interceptors works too
// axiosInstance.defaults works too
export default axiosInstance;
Now you can use axiosInstance for HTTP requests and even create multiple instances.
Pro tip: Instances work because of prototypal inheritance! You're overriding default behaviour in the global axios object. If you don't override, axiosInstance will inherit axios properties.
Error Handling HOC
Using interceptors, we can create a higher-order component that handles any axios errors and displays them. Here's the basic code:
const withErrorHandler = (WrappedComponent, axios) => {
return props => {
// Create error state
const [error, setError] = useState(null)
// On mount, add axios interceptors to axios instance USED BY WrappedComponent
useEffect(() => {
axios.interceptors.request.use(req => {
setError(null) // <= Reset error state on new request
return req
})
axios.interceptors.response.use(res => res, err => {
setError(err) // <= Set error state
return Promise.reject(err)
})
}, [setError])
return (
<>
<Modal {/* <= We're using a modal to display the error */}
show={error ? true : false}
>
{error ? error.message : null}
<Modal />
<WrappedComponent {...props} /> {/* <= Passing props down to component */}
</>
)
}
}