Axios is one of the favorite HTTP clients among Javascript developers. It is a promise-based HTTP client used to send HTTP requests, especially AJAX requests, from the client side as well as the server side.
Sending HTTP requests from the Javascript side is now almost a necessity when developing dynamic web applications. Axios simplifies this task by providing an easy-to-use abstraction over Javascript’s XMLHttpRequest interface with several user-friendly functions and configuration options.
In this tutorial, we will walk through everything you need to know about sending HTTP requests with Axios with code examples and simplified explanations.
Let’s start our introduction with this question.
Why You Should Choose Axios?
Axios has several advantages over other HTTP clients, such as jQuery’s AJAX, the native XMLHttpRequest library, and fetch. It is a lightweight package with excellent support for client-side and server-side requests, which means it can run on NodeJS or the browser.
The syntax of Axios is simple and intuitive, making it easy to work with even for novice developers.
Recently the Fetch API has been gaining some popularity for sending requests. However, Axios still provides several advantages over the same:
- Support for request and response interception
- Ability to cancel Axios requests
- Automatic transforms for JSON data (Axios serializes javascript objects into JSON and vice versa)
- Automatic data object serialization to
multipart/form-data
andx-www-form-urlencoded
body encodings - Client-side support for XSRF protection
How to install Axios
You can install and use Axios on both the front-end and back-end. The installation is simple if you are using a package manager like npm.
npm install axios
If you use a content delivery network (CDN), embed the Axios script in HTML.
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
Or,
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Send HTTP Requests with Axios
Axios is simple. To start an HTTP request, you can use the Axios main function, passing an object with all the request parameters, options, and data like in the following example:
axios({
method: "post",
url: "/users",
data: {
username: "sam123",
firstname: "sam",
lastname: "smith"
}
});
As can be identified, the Axios library will initiate a POST request against the given URL and send some data to the server.
That's a simple example, but Axios provides much more features that can be enabled in this request object. To learn more about it, refer to its official documentation.
That's way number one to send requests, but there is another, which I prefer as it is more explicit, which is using dedicated request functions for each HTTP method.
Here is the list of supported methods:
axios.delete(url[, config]);
axios.head(url[, config]);
axios.options(url[, config]);
axios.post(url[, data[, config]]);
axios.put(url[, data[, config]]);
axios.patch(url[, data[, config]]);
Axios GET request example
The beauty of Axios is in its simplicity while giving the user multiple options. Say, for instance, that you need to make a GET request to the URL: /users?firstName=jc
. You could simply write the following Axios GET request code:
axios.get('/user', {
params: {
firstName: 'jc'
}
})
.then(function (response) {
// handle success
console.log(response);
});
But alternatively, you can pass the parameters as part of the URL string. However, This may not be a best practice; it's cleaner when working with variables, and Axios will automatically sanitize the inputs, which won't do if you provide the values directly as part of the URL.
But in some cases, it makes sense to avoid sanitization, e.g., when sending certain API keys over query parameters. Here is the same request not using params
.
axios.get('/user?firstName=jc')
.then(function (response) {
// handle success
console.log(response);
});
Both examples of Axios GET requests handle only the happy path, but since Axios is promise based, you can also catch errors and run code in either condition.
Axios POST Request Example
When working with POST requests (also similar to PATCH and PUT), it is very common to send data to the server, and if you are working with REST APIs, chances are you are sending data in JSON format. The beauty of Axios in working with REST is that it will automatically transform JS objects into JSON when sending data and will convert the responses from JSON into JS objects so that you can directly work with them.
Let's see an example of an Axios POST request.
axios.post('/user', {
firstName: 'jc',
lastName: 'M'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
With Axios, there's no need to convert JS objects or stringify, you simply pass the Axios POST request the URL and the object, and Axios will take care of everything else.
Handle Responses with Axios
When we send an HTTP request to a remote server, we receive a response from that server containing certain information. We can retrieve this response using Axios.
According to Axios documentation, the returned response contains the following information.
{
// `data` is the response that was provided by the server
data: {},
// `status` is the HTTP status code from the server response
status: 200,
// `statusText` is the HTTP status message from the server response
statusText: 'OK',
// `headers` the HTTP headers that the server responded with
// All header names are lower cased and can be accessed using the bracket notation.
// Example: `response.headers['content-type']`
headers: {},
// `config` is the config that was provided to `axios` for the request
config: {},
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance in the browser
request: {}
}
Since Axios is promise-based, the response is returned as a promise. So we need to use then()
and catch()
functions to retrieve the response and catch errors if there are any.
Let’s see how we can handle the response returned by a POST request.
axios.post("/users", {
username: "sam123",
firstname: "sam",
lastname: "smith"
})
.then(response => {
console.log(response);
console.log(response.data);
console.log(response.data.userId);
console.log(response.status);
console.log(response.statusText);
})
.catch(error => {
console.log(error.message);
});
Use Async/Await
We can also use async/await to send HTTP requests and handle responses instead of promises.
async function getUserData() {
try {
const response = await axios.get("/users/sam123");
console.log(response);
}
catch (error) {
console.log(error);
}
}
Working with concurrent requests
In the previous section, we used Promise.all() method to send multiple concurrent requests. When all the requests passed to the method are completed, it returns a single promise with response objects of every request. We can separate the responses using the index of each request in the array passed to the method.
Promise.all([
axios.get("/users/sam123"),
axios.get("/users/sam123/comments")
])
.then(response => {
const user = response[0].data
const comments = response[1].data
})
.catch(error => {
console.log(error);
});
Error handling with Axios and HTTP status code
If an error occurs when sending an HTTP request with Axios, the returned error object contains specific information to help us determine exactly where the error occurred.
Errors could occur in any of the following three areas:
- The request responded with a status code out of the range of 2xx
- Time out, the request was made, but no response was received
- Something else blew up when setting up the request
With Axios, you can identify these different scenarios and act accordingly. Here is some example code that can help you get started
axios.get('/user?firstName=jc')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// Time out, the request was made, but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something else blew up when setting up the request
console.log('Error', error.message);
}
console.log(error.config);
});
Transform Data with Axios
We talked about how Axios will transform data automatically into and from JSON for you, but what if you require any other transformations? For example, working with some APIs is common to see attributes in snake-case (e.g., first_name). However, we don't want snake-case in our JS code. We want something like "firstName" instead.
For purposes like these, Axios provides a feature that allows you to transform requests and responses with two simple functions:
axios({
method: "post",
url: "users/sam123",
data: {
username: "sam123",
firstname: "sam",
lastname: "smith"
},
// `transformRequest` allows changes to the request data before it is sent to the server
// This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'
// The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
// FormData or Stream
// You may modify the headers object.
transformRequest: [(data, headers) => {
//Transform request data as you prefer
return data;
}],
// `transformResponse` allows changes to the response data to be made before
// it is passed to then/catch
transformResponse: [(data) => {
//Transform the response data as you prefer
return data;
}]
});
Intercept Requests
HTTP request interception is one of the most interesting features in Axios. It allows you to intercept requests sent by and requests received by your program and carry out some common tasks before the operation is complete. This feature simplifies handling background tasks related to HTTP requests, such as logging, authentication, and authorization.
Defining an interceptor for either requests or responses is a simple task.
axios.intercept.request.use(config => {
//Intercept the request and do something before it is sent
console.log("Request sent");
return config;
}, error => {
return Promise.reject(error);
});
axios.get("/users/sam123")
.then(response => {
console.log(response.data);
});
Here, the config object is the exact config object we pass the Axios function or one of its aliases. So the interceptor has full access to the request config and its data.
After setting the request interceptor, every time a new request is sent by the program, we print the message: "Request sent" to the console.
We can similarly set a response interceptor.
axios.intercept.response.use(config => {
//Intercept the response and do something when it is received
console.log("Response recieved");
return config;
}, error => {
return Promise.reject(error);
});
axios.get("/users/sam123")
.then(response => {
console.log(response.data);
});
Every time we receive a response, we print the message: "Response received" to the console.
We can define interceptors for instances instead of the Axios object as well.
instance.intercept.request.use(config => {
//Intercept the request and do something before it is sent
console.log("Request sent");
return config;
}, error => {
return Promise.reject(error);
});
Cancel Requests with Axios
There are some cases in web development where we might find the response from the remote server to our request is no longer important. In such cases, we can save the system resources by simply canceling the request (I know, most of the time, developers don't, but we should). And Axios provides us with a method to do just that, in a very similar way to Fetch, by using the AbortController.
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// cancel the request
controller.abort()
You may see in some older code the use of the Axios cancel token API. However, that method has been deprecated by the more friendly and standard AbortController.
Set Custom Headers for Requests
You can easily set custom headers for the requests you are sending with Axios. You only have to pass an object containing the custom headers to the request method you are using.
const options = {
headers: {"X-Custom-Header": "value"}
}
axios.get("users/sam123", options);
Set Config Defaults
In a given application is common to have a base set of configurations that would apply to all web requests; it could be something like a base URL, some headers, etc. But if your application uses Axios multiple times in multiple files, it could end up being messy to repeat the same code over and over again.
That's where config defaults come in. They allow you to set default configuration options for all Axios requests.
For example, if you want to set the base URL or an authorization header for every request, it can be easily achieved, as the following example shows.
axios.defaults.baseURL = "https://example.com";
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN
Set Config Defaults of Instances
Sometimes, setting default configurations for every HTTP request becomes unrealistic due to the differences in requests we send: we could send requests to two different APIs or with different authorization tokens depending on the user permissions.
In such cases, though we are not able to find config options common to every request, we might be able to find options common to different groups of requests. Axios provides us with a way to set default configs for these different groups separately.
It’s by creating instances.
We can create separate instances and set default configs for each instance. Then, we can use this instance object to send requests instead of the Axios object.
// Create new instance
const instance = axios.create();
// Set config defaults for the instance
instance.defaults.baseURL = "https://example.com";
instance.defaults.headers.common["Authorization"] = AUTH_TOKEN;
// Send requests using the created instance
instance.get("/users", {
params: {
firstname: "sam"
}
});
Protect against XSRF Attacks
Cross-site request forgery (XSRF) is a technique used by attackers to infiltrate web applications and carry out malicious tasks. In these attacks, the attacker disguises as a trusted user and tricks the application into executing actions for their benefit.
This could compromise the privacy and security of the user and even result in the attacker gaining access to the entire system if the user has high-level permission.
Axios provides a way to prevent such attacks by embedding additional authentication information when creating the request. This is how it is implemented.
const options = {
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
};
axios.post("/users", options);
Popular Axios libraries to extend its functionality
- axios-mock-adapter: Axios adapter that allows easy mock requests
- axios-hooks: React hooks for Axios, with built-in support for server-side rendering.
- axios-retry: Axios plugin that intercepts failed requests and retries them whenever possible.
- moxios: Mock Axios requests for testing
- axios-extensions: 🍱 Axios extensions lib, including throttle, cache, retry features, etc...
- axios-cache-adapter: Caching adapter for Axios. Store request results in a configurable store to prevent unneeded network requests.
- axios-curlirize: Axios plugin converting requests to cURL commands, saving and logging them.
FAQs
Can I use Axios with React, Vue, or Angular?"
Yes, you can use Axios with React or any other JS framework, as Axios can run on the browser or the server.
What is the difference between Fetch API and Axios?
Axios provides more features out of the box than Fetch API; with that said, all those features have equivalents with Fetch but would require more code to get them to work. So if you don't mind installing a lightweight library to handle your requests, Axios is a great option, with more features and a very likable API.
Can I mock Axios for unit testing?"
Yes, you can write unit tests for applications using Axios, and you can mock the Axios API. Here is an example:
import axios from 'axios';
// Mock out all top level functions, such as get, put, delete and post:
jest.mock("axios");
// ...
test("good response", () => {
axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
// ...
});
test("bad response", () => {
axios.get.mockImplementation(() => Promise.reject({ ... }));
// ...
});
Conclusion
In this article, we explained what Axios is and why it is a great choice for your project. We also gave examples of working with GET and POST requests and more advanced features like API intercept request, default request config, transforms, handling errors, and more.
Axios is a great library for making HTTP requests, and it provides developers with many features that can help them make the most out of their applications. We hope this article has provided enough information to use Axios in your projects.
Thanks for reading, and happy requests!
Newsletter
Subscribe to my weekly newsletter for developers and builders and get a weekly email with relevant content.
Top comments (0)