This tutorial covers:
- Why use Axios?
- Making Axios POST and GET requests
- Testing the requests
Axios is a promise-based HTTP library that lets developers make requests to either their own or a third-party server to fetch data. It offers different ways of making requests such as GET
, POST
, PUT/PATCH
, and DELETE
. In this tutorial, I will explain how Axios interacts with applications, describe the structure of Axios requests and responses, how to make requests to an API, and how to write tests for your requests using CircleCI.
Prerequisites
To follow along with the tutorial, make sure that you have:
- NodeJS installed in your system.
- A GitHub account.
- A CircleCI account.
- A basic understanding of JavaScript and unit testing.
How does Axios work?
Axios works by making HTTP requests with NodeJS and XMLHttpRequests on the browser. If the request was successful, you will receive a response
with the data requested. If the request
failed, you will get an error. You can also intercept
the requests and responses and transform or modify them. I will go into more detail about that later in this tutorial.
This diagram shows a representation of how Axios interacts with an application.
Axios determines whether the request is made to the browser or to NodeJS. It then identifies the proper way to make the API requests and returns a transformed response back to the client that made the server request.
Axios request and response configurations
Making a basic request in Axios is easy because the only option required is the url
. However, you can configure other options depending on the kind of request that you want to make.
Here is an example request:
const axios = require('axios');
const res = await axios.get(url, {
//We can add more configurations in this object
params: {
//This is one of the many options we can configure
}
});
// This is the second configuration option
const res = await axios({
method: 'get',
url://Endpoint goes here,
params:{
}
});
Axios provides great flexibility for configuring your requests. You can decide to call Axios with the JavaScript dot notation format. Or you can use the object literal format to bundle all the Axios request properties into an object to use as properties of making the Axios request.
There are several methods that Axios supports and that are allowed to make requests. They include:
request
get
delete
head
options
post
put
patch
The next code snippet shows how to use a sample GET
request sent to a Todos
sample API using Axios.
axios({
method: "get",
url: "https://jsonplaceholder.typicode.com/todos",
params: {
_limit: 5,
},
});
Axios responses
Once you send a request with Axios, you expect to have a response returned. This snippet shows the data structure of an Axios response:
{
// `data` is the response that was provided by the server
data: {},
// `status` is the HTTP status code from the response
status: 200,
// `statusText` is the status message from the response
statusText: 'OK',
// `headers` are the HTTP headers that the server responded with
headers: {},
// `config` is the config that was provided to `axios` for the request
config: {},
// `request` is the request that generated the response
request: {}
}
In this response, you get:
- Object of the data that you are expecting
- Status code sent back by the server
- StatusText
- Response headers
- Config object set by Axios
- Request object used to generate the response
You can then consume the responses on your client-side application depending on the data that you need.
Is this is feeling like a lot of theoretical knowledge? If so, move on to the next section, where I will show you exactly how to make HTTP requests with Axios.
Making Axios HTTP requests
In this section, you will make GET
and PUT
requests, and observe concurrent requests. You will be using a free “fake” API: JSONPlaceholder.
You will also use an application that will help you make your requests and get a better view of what is happening under the hood.
Before you get started though, you need to clone the GitHub repository for the tutorial. Run these commands:
git clone https://github.com/CIRCLECI-GWP/making-http-requests-axios
cd making-http-requests-axios
Now you should have the files you need for this tutorial. Your next step is to install both Axios and Jest as dependencies. Run this command:
npm install
Open the index.html
file on the browser to review your Axios demo webpage.
For now, the buttons do not do anything. We will build the functionality later in the tutorial.
There are three buttons for each request. Clicking a button should display a response after the Axios request has been made and data returned to the browser.
In the users.js
file of your cloned repository, there is an event listener that displays the data returned by Axios. This file also has functions you will use to make your requests. Get started by making your first GET
request.
Making a GET request
This snippet shows what your request should look like:
axios
.get("https://jsonplaceholder.typicode.com/users/1")
.then((response) => {
displayOutput(response);
})
.catch((err) => console.log(err));
This code snippet sends a GET
request to the JSON API. Because the request returns a promise, you will use the .then()
block to handle the responses. You will also need to use the .catch()
method to log any errors to the console.
Add the previous code snippet to the getUser()
function in the users.js
file and save it.
Next, go to the browser and click the GET
button. Below it, new content should appear, displaying details of the response.
Styling and display has already been completed. The sections of the received Axios response are:
- The
status
section, which displays the status code of the response. In this case it is200
, which means that the request was successful. - The
headers
section, which contains all the HTTP headers that the server responds with. - The
data
section, which contains the payload or the information that was requested from the server. In this case, it is all the information aboutuser 1
. - The
config
section, which contains all the configuration that was passed to Axios for the request.
As shown in the request, Axios behaves like the traditional fetch-API
library. Considering that this is a GET
request, you do not need to pass a body with a request. Next I will show you how to do that in a POST
request using Axios.
Making a POST request
A post request is a little different because you will be passing some data in the request to the server. In the request, you will be creating a user and passing in details for that user. The code snippet for the request will look something like this:
axios
.post("https://jsonplaceholder.typicode.com/users", {
id: 11,
name: "Tom Brady",
username: "Brad",
email: "tombrad@asd.com",
})
.then((response) => displayOutput(response))
.catch((err) => console.log(err));
The Axios POST request uses an object after the request URL to define the properties you want to create for your user. Once the operation has been completed, there will be a response from the server. To verify that your code is working, go back to the application browser window and click the POST button. This snippet is part of the postUser()
function in the users.js
file.
A POST
response differs a little from a GET
request:
- The
status
section has a status code of201
, which means a resource has been created. In this case, a new user has been created. - The
headers
section has a‘content-length’
property for the length of the data we sent. It also specifies where the data will be stored:location
. - The
data
section contains the information that was sent to the server. - The
config
section contains the configuration that was sent along with the request. This involves themethod
,url
, anddata
being sent.
You can verify that the data defined in your POST
request is the exact response received from the server as a created resource.
In this section, you learned how to make an Axios request, and I have described the basic structure of an Axios request and its expected responses. In the next section, I will explain how to request interception to verify data before it is sent to Axios as a request.
Axios request and response interceptors
Interception in Axios happens when requests are intercepted before they are handled by the then()
or the catch()
code block. For example, say you want to check that all the requests going through to a client have a valid JWT token. You would set up a request interceptor to make sure that all the calls made to the server have that valid token. If a call does not have a valid token, the users of the system would have to go back to the log in page and be re-authenticated. In the interests of time, I will lead you through a less complicated use case, writing a logger for your current application.
The logger will log when a request was made, the URL for the request, and the time when the request was triggered. Use this code snippet:
axios.interceptors.request.use(
(config) => {
const today = new Date();
console.log(
`${config.method.toUpperCase()} request sent to ${
config.url
} at ${today.getHours()} : ${today.getMinutes()}`
);
return config;
},
(error) => {
console.log(error);
}
);
Axios will access the config
section of your requests to display the request method, URL, and time. This code snippet is part of the users.js
file in the interceptRequests()
function of the sample project. To observe the behavior of the Axios interceptor, open the Chrome browser console. Click the GET
method that fetches the first user in the API
For the interceptors to work, they need to be called as concurrent requests to the jsonplaceholder
API. The next code snippet shows Axios methods that implement the requests and responses:
const concurrentRequests = () => {
interceptRequests();
axios
.all([
axios.get("https://jsonplaceholder.typicode.com/users?_limit=5"),
axios.get("https://jsonplaceholder.typicode.com/albums?_limit=5"),
])
.then(
axios.spread((users, albums) => {
displayOutput(albums);
})
)
.catch((err) => console.log(err));
};
The Chrome DevTools image shows that when you make any request, you can modify or inspect it before it is sent by Axios to the API server. Axios interceptors are not only powerful, they give developers the ability to control requests and the behavior of their responses.
Now you have learned how to use interceptors to modify or inspect your Axios requests and responses. Great work! Your next task is writing tests for your Axios implementation.
Testing the Axios implementation
Testing is an integral process for developing any application. Tests help make sure your application works as intended and that quality is consistent throughout. In this section of the tutorial, you will use the node.js
version of Axios. Since you already installed Jest while installing dependencies, you can start writing tests right away.
In the root directory, create two files and name them app.js
and app.test.js
. Use app.js
for your requests and app.test.js
for your tests. You need to re-create the app.js
file to make sure that you can access the methods that use the Node.js
Axios - not the browser Axios defined in the script
section of your index.html
file.
In the app.js
file, you can use axios
to make requests in Node.js
. This method uses the same request structure as the browser method does:
const axios = require("axios");
const getUser = async () => {
const getResponse = await axios
.get("https://jsonplaceholder.typicode.com/users/1")
.then((response) => response)
.catch((err) => console.log(err));
return getResponse;
module.export = { getUser };
};
This snippet makes a request to the same URL used earlier and then saves the response to the getResponse
variable. It then returns the response to make it accessible to other methods or functions that may need it — like our tests. The snippet exports the method to make it accessible outside the app.js
file.
To write a test for this, import the getUser
method into your app.test.js
test file. Then write your test as shown here:
const { getUser, postUser, concurrentRequests } = require("./app.js");
describe("Axios requests suite", () => {
test("should get a single user", async () => {
const response = await getUser();
expect(response).not.toBeNull();
expect(response.status).toBe(200);
expect(response.data.address.street).toContain("Kulas");
});
}
Using this test and the sample response object, you can verify that the data called from the Axios endpoint was returned and that your API call was successful. To run this test, go to your terminal and use the Jest command npm test
:
PASS ./app.test.js
Axios requests suite
✓ should get a single user (144 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.266 s, estimated 1 s
Ran all test suites.
Success! Now you can write more tests, for the POST
request and the concurrent requests using Axios.
In the same file, add these tests:
test("should post a new user", async () => {
const response = await postUser();
expect(response).not.toBeNull();
expect(response.status).toBe(201);
expect(response.data.username).toBe("Brad");
});
test("should make simultaneous axios requests", async () => {
const response = await concurrentRequests();
expect(response).not.toBeNull();
expect(response.status).toBe(200);
});
When you are done, rerun your tests.
npm run test
Again, success!
Now that you have written Axios requests and tested them, you can build a CI pipeline for them. Using a CI/CD tool like CircleCI keeps everyone informed when changes break the pipeline and cause the tests to fail. This kind of feedback loop provides the insight and transparency needed in a successful software development process.
Integrating with CircleCI
Create a .circleci
folder and inside it, a file named config.yml
. This is CircleCI’s configuration file. In the file, add this configuration:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: cimg/node:19.0.1
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: install dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Axios request tests
command: npm run test
- store_artifacts:
path: ~/repo/axios-http-requests
This configuration defines your working_directory
, then tells CircleCI to use a Node image to execute your tests. Once that is set up, it checks for any stored cache for the project. If there is one, it needs to be restored before doing a new dependencies install. The cache is saved after installing new dependencies, tests are executed, and any artifacts that were generated are saved.
Now you need to save the configuration file, commit, and push the changes to your GitHub repository. Then, log into the CirclecI dashboard. Find the GitHub repository for the tutorial in the Projects section. In our case, it is called making-http-requests-axios
. Click Set Up Project.
When prompted, enter the name of the branch that has your config.yml
file. For this tutorial, it is the main
branch. Then, click Set up Project.
Note: GitLab users can also follow this tutorial by pushing the sample project to GitLab and setting up a CI/CD pipeline for their GitLab repo.
You have a successful pipeline build! Review the details by clicking the build
workflow.
Click the steps you want more detail about; for example, the Axios requests tests
step.
CircleCI detects changes every time you push to the GitHub repository in your main
branch. The CircleCI pipeline will execute again and make sure that your test suite runs, ensuring a successful continous integration process.
I enjoyed creating this tutorial for you, and I hope you found it valuable. Until next time, keep coding!
Waweru Mwaura is a software engineer and a life-long learner who specializes in quality engineering. He is an author at Packt and enjoys reading about engineering, finance, and technology. You can read more about him on his web profile.