Using Axios for HTTP Requests

A comprehensive guide on using Axios for HTTP requests in JavaScript, covering installation, making requests, handling responses, configuring requests, and best practices.

Welcome to this detailed guide on using Axios for HTTP requests in JavaScript. Axios is a popular library that makes it easy to send asynchronous HTTP requests to REST endpoints and perform CRUD operations. Whether you're building a web application, a mobile app, or a server-side application, understanding how to effectively use Axios is an essential skill.

In this comprehensive guide, you'll learn how to install Axios, make different types of HTTP requests, handle responses, configure requests, manage headers, work with JSON data, use interceptors, handle errors, and more. We will also touch on advanced topics like canceling requests, sending concurrent requests, and customizing responses. By the end of this guide, you'll be well-equipped to handle HTTP requests in your JavaScript projects.

Installing Axios

Before diving into making HTTP requests, you need to install Axios. Axios can be installed using npm or by including it via a CDN.

Using npm

If you're using Node.js or a build tool like Webpack, you can install Axios via npm:

npm install axios

Once you've installed Axios, you can import it into your JavaScript file:

// Importing Axios in an ES6 module
import axios from 'axios';

Using a CDN

If you're working in a simple HTML file or prefer not to use npm, you can include Axios via a CDN:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Axios Example</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
</body>
</html>

By including the CDN link, Axios will be available in the global scope as axios.

Making Your First Request

Now that you have Axios installed, let’s start making HTTP requests.

Sending a GET Request

The GET method is used to retrieve data from a server. Here's an example of how to send a GET request to the JSONPlaceholder API to fetch a list of users:

// Sending a GET request using Axios
axios.get('https://jsonplaceholder.typicode.com/users')
    .then(function (response) {
        // Handle success
        console.log(response.data);
    })
    .catch(function (error) {
        // Handle error
        console.log(error);
    })
    .then(function () {
        // Always executed
        console.log('This is always executed regardless of the request result');
    });

In this example, we use axios.get() to make a GET request. The then() method handles the response, the catch() method handles errors, and the final then() method is always executed, making it ideal for cleanup operations.

Expected output:

[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    ...
  },
  ...
]

Sending a POST Request

The POST method is used to send data to a server to create/update a resource. Here's an example of how to send a POST request to create a new user:

// Sending a POST request using Axios
axios.post('https://jsonplaceholder.typicode.com/users', {
    name: 'John Doe',
    username: 'johndoe',
    email: 'john@example.com'
})
    .then(function (response) {
        // Handle success
        console.log(response.data);
    })
    .catch(function (error) {
        // Handle error
        console.log(error);
    });

This example sends a POST request with a JSON object containing user data. The server responds with the created user object, which includes the server-generated ID.

Expected output:

{
  "name": "John Doe",
  "username": "johndoe",
  "email": "john@example.com",
  "id": 11
}

Sending a PUT Request

The PUT method is used to update an existing resource. Here's an example of how to update a user's email using a PUT request:

// Sending a PUT request using Axios
axios.put('https://jsonplaceholder.typicode.com/users/1', {
    email: 'newemail@example.com'
})
    .then(function (response) {
        // Handle success
        console.log(response.data);
    })
    .catch(function (error) {
        // Handle error
        console.log(error);
    });

This example updates the email of the user with ID 1. The server responds with the updated user data.

Expected output:

{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "newemail@example.com",
  ...
}

Sending a DELETE Request

The DELETE method is used to delete a resource. Here's an example of how to delete a user:

// Sending a DELETE request using Axios
axios.delete('https://jsonplaceholder.typicode.com/users/1')
    .then(function (response) {
        // Handle success
        console.log(response.data);
    })
    .catch(function (error) {
        // Handle error
        console.log(error);
    });

This sends a DELETE request to remove the user with ID 1. The response usually contains the status and the deleted resource.

Expected output:

{}

Note that the server response might vary based on the API. In many cases, the server may return an empty object or a 204 No Content status code.

Understanding Responses

After you make an HTTP request, you'll receive a response from the server. The response contains important information that you can use to perform various operations.

Response Structure

The response from Axios includes several properties:

Data

The data property contains the response payload returned from the server. For example, in the GET request we made earlier, response.data contained the user data.

Status

The status property contains the HTTP status code returned by the server. Common status codes include:

  • 200 OK: The request has succeeded.
  • 201 Created: The request has been fulfilled and has resulted in one or more new resources being created.
  • 400 Bad Request: The server could not understand the request due to invalid syntax.
  • 404 Not Found: The server can't find the requested resource.
  • 500 Internal Server Error: The server has encountered a situation it doesn't know how to handle.

Here’s how you can check the status of a response:

// Checking the status of a response
axios.get('https://jsonplaceholder.typicode.com/users/1')
    .then(function (response) {
        console.log('Status:', response.status); // e.g., 200
    })
    .catch(function (error) {
        console.log(error);
    });

Headers

The headers property contains the HTTP headers that the server used when it responded to the request. You can access specific headers or loop through all of them.

Here’s how you can check the headers of a response:

// Checking the headers of a response
axios.get('https://jsonplaceholder.typicode.com/users/1')
    .then(function (response) {
        console.log(response.headers);
        // Access a specific header
        console.log('Content-Type:', response.headers['content-type']);
    })
    .catch(function (error) {
        console.log(error);
    });

Configuring Requests

Axios allows you to configure requests to suit your needs. There are different levels of configuration available: global, instance, and request.

Global Configuration

Global configuration affects all requests. Here’s how you can set a base URL globally:

// Setting global configuration
axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/json';

// Now you can make requests without specifying the full URL
axios.get('/users/1')
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Instance Configuration

Instance configuration affects only the instance it was set on. Here’s how to create and configure an Axios instance:

// Creating an Axios instance
const instance = axios.create({
    baseURL: 'https://jsonplaceholder.typicode.com',
    timeout: 1000, // Request times out after 1 second
    headers: {'X-Custom-Header': 'foobar'}
});

// Using the instance
instance.get('/users/1')
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Request Configuration

Request configuration is specific to a single request. Here’s an example of setting configuration for a single request:

// Configuring a single request
axios.get('https://jsonplaceholder.typicode.com/users/1', {
    timeout: 2500,
    headers: {'X-Custom-Header': 'uniqueValue'}
})
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Headers

Headers are name-value pairs that provide additional information about the request or response.

Setting Headers for Requests

You can specify headers for your requests in various ways, including instance and request configurations.

// Setting headers for a single request
axios.get('https://jsonplaceholder.typicode.com/users/1', {
    headers: {'X-Custom-Header': 'value'}
})
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Checking Response Headers

You can access response headers from the response object.

// Checking response headers
axios.get('https://jsonplaceholder.typicode.com/users/1')
    .then(function (response) {
        console.log(response.headers);
    })
    .catch(function (error) {
        console.log(error);
    });

Common Headers

Some headers are commonly used, such as Content-Type and Authorization.

// Setting common headers globally
axios.defaults.headers.common['Content-Type'] = 'application/json';
axios.defaults.headers.common['Authorization'] = 'Bearer yourAuthToken';

URL Parameters and Query Strings

URL parameters and query strings are ways to send data as part of the URL.

Using Query Strings in Requests

Query strings are used to send additional data to the server in a structured query string format. Here’s how to include query strings:

// Using query strings in a request
axios.get('https://jsonplaceholder.typicode.com/users', {
    params: {
        name: 'John Doe'
    }
})
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

The query string will be appended to the URL automatically.

Using URL Parameters

URL parameters allow you to include dynamic data in the URL path. Here’s how to include URL parameters:

// Using URL parameters in a request
const userId = 1;
axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`)
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

In this example, userId is included in the URL path.

Encoding Query Strings

Axios automatically encodes query strings for you. However, if you need to manually encode a query string, you can use encodeURIComponent:

// Manually encoding query strings
const encodedQuery = encodeURIComponent("John Doe");
axios.get(`https://jsonplaceholder.typicode.com/users?name=${encodedQuery}`)
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

This ensures that special characters are properly encoded.

Handling JSON Data

JSON is the most commonly used format for sending and receiving data in HTTP requests.

Sending JSON Data

When sending JSON data, Axios automatically sets the Content-Type header to application/json. Here’s an example of sending JSON data in a POST request:

// Sending JSON data
axios.post('https://jsonplaceholder.typicode.com/users', {
    name: 'John Doe',
    username: 'johndoe',
    email: 'john@example.com'
})
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Receiving JSON Data

Axios automatically parses JSON data when the Content-Type header is set to application/json. Here’s how to receive JSON data:

// Receiving JSON data
axios.get('https://jsonplaceholder.typicode.com/users')
    .then(function (response) {
        // response.data is automatically parsed as JSON
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Interceptors

Interceptors allow you to intercept requests or responses before they are handled by then or catch.

Request Interceptors

You can use request interceptors to modify requests before they are sent. This is useful for adding authentication tokens or logging requests.

// Adding a request interceptor
axios.interceptors.request.use(function (config) {
    console.log('Request Config:', config);
    // Add an authorization token to the header
    config.headers.Authorization = 'Bearer yourAuthToken';
    return config;
}, function (error) {
    // Handle request errors
    return Promise.reject(error);
});

Response Interceptors

You can use response interceptors to modify responses before they are handled by then or catch. This is useful for logging responses or handling errors globally.

// Adding a response interceptor
axios.interceptors.response.use(function (response) {
    // Any status code within the range of 2xx cause this function to trigger
    // Do something with response data
    console.log('Response received:', response);
    return response;
}, function (error) {
    // Any status codes outside the range of 2xx cause this function to trigger
    // Do something with response error
    console.error('Response error:', error);
    return Promise.reject(error);
});

Error Handling

Handling errors is crucial for robust applications. Axios provides several ways to handle errors.

Basic Error Handling

You can handle errors using the catch() method:

// Basic error handling
axios.get('https://jsonplaceholder.typicode.com/users/1000')
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log('Error fetching user:', error);
    });

Catching Errors

Axios allows you to catch different types of errors, such as network errors or server errors.

// Catching different types of errors
axios.get('https://jsonplaceholder.typicode.com/users/1000')
    .then(function (response) {
        console.log(response.data);
    })
    .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) {
            // The request was made but no response was received
            console.log(error.request);
        } else {
            // Something happened in setting up the request that triggered an Error
            console.log('Error', error.message);
        }
        console.log(error.config);
    });

Using the validateStatus Option

You can customize the validateStatus function to define what status codes should be considered a valid response.

// Customizing the validateStatus function
axios.get('https://jsonplaceholder.typicode.com/users/1000', {
    validateStatus: function (status) {
        return status < 300; // only return status < 300 as valid
    }
})
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Advanced Topics

Canceling Requests

Sometimes you might need to cancel a request before it completes, for example, when a user navigates away from a page. Here’s how to cancel a request:

// Canceling a request
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('https://jsonplaceholder.typicode.com/users/1', {
    cancelToken: source.token
})
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (thrown) {
        if (axios.isCancel(thrown)) {
            console.log('Request canceled', thrown.message);
        } else {
            // handle error
            console.log(thrown);
        }
    });

// Cancel the request
source.cancel('Operation canceled by the user.');

Sending Concurrent Requests

You can send multiple requests concurrently using axios.all() and axios.spread().

// Sending concurrent requests
axios.all([
    axios.get('https://jsonplaceholder.typicode.com/users/1'),
    axios.get('https://jsonplaceholder.typicode.com/posts?userId=1')
])
    .then(axios.spread(function (user, posts) {
        console.log(user.data);
        console.log(posts.data);
    }))
    .catch(function (error) {
        console.log(error);
    });

Using Promises

Axios uses Promises, which means you can use async/await for cleaner asynchronous code.

// Using async/await with Axios
(async () => {
    try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/users/1');
        console.log(response.data);
    } catch (error) {
        console.log('Error:', error);
    }
})();

Axios Instance

Creating an Axios instance is useful when you need to make requests with a specific configuration.

Creating an Instance

You can create an Axios instance with a custom configuration:

// Creating an Axios instance
const api = axios.create({
    baseURL: 'https://jsonplaceholder.typicode.com',
    timeout: 1000,
    headers: {'X-Custom-Header': 'value'}
});

Configuration of an Instance

You can set default configuration for an instance:

// Setting default configuration for an instance
api.defaults.headers.common['Authorization'] = AUTH_TOKEN;
api.defaults.headers.post['Content-Type'] = 'application/json';

Using an Instance

You can use the instance to make requests using the default configuration:

// Using the instance to make a request
api.get('/users/1')
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Customizing the Axios Response

You can customize how response data and headers are handled.

Customizing Response Data

You can transform the response data using the transformResponse option:

// Customizing response data
axios.get('https://jsonplaceholder.typicode.com/users/1', {
    transformResponse: [(data) => {
        // Transform data
        return JSON.parse(data).name;
    }]
})
    .then(function (response) {
        console.log(response.data); // Outputs the user's name
    })
    .catch(function (error) {
        console.log(error);
    });

Customizing Response Headers

You can manipulate the headers before they are returned to your application:

// Customizing response headers
axios.get('https://jsonplaceholder.typicode.com/users/1', {
    transformResponse: [(data, headers) => {
        // Transform data and headers
        headers['X-Custom-Header'] = 'customValue';
        return JSON.parse(data);
    }]
})
    .then(function (response) {
        console.log(response.data);
        console.log(response.headers);
    })
    .catch(function (error) {
        console.log(error);
    });

Testing with Axios

Testing HTTP requests is crucial for ensuring your application works as expected.

Mocking Axios Requests

For testing purposes, you might want to mock Axios requests. You can do this using libraries like axios-mock-adapter.

// Importing axios-mock-adapter
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';

// Creating a mock adapter
const mock = new MockAdapter(axios);

// Mocking GET request
mock.onGet('/users/1').reply(200, {
    id: 1,
    name: 'John Doe',
    email: 'johndoe@example.com'
});

// Making the GET request
axios.get('/users/1')
    .then(function (response) {
        console.log(response.data);
    })
    .catch(function (error) {
        console.log(error);
    });

Using Test Frameworks with Axios

You can use test frameworks like Jest to test Axios requests. Here’s a simple example:

// Using Jest to test Axios request
import axios from 'axios';

test('fetches users', async () => {
    const response = await axios.get('https://jsonplaceholder.typicode.com/users/1');
    expect(response.data.name).toBe('Leanne Graham');
});

Best Practices

Security Considerations

  • Always validate and sanitize inputs to prevent injection attacks.
  • Use HTTPS to protect data in transit.
  • Avoid logging sensitive information in error messages.

Performance Considerations

  • Use caching strategies to reduce the number of requests.
  • Use Axios interceptors to combine multiple API calls when possible.
  • Monitor request and response times to optimize performance.

Code Quality Considerations

  • Use descriptive variable and function names.
  • Write modular and reusable code.
  • Document your code for future maintenance.

By following these best practices, you can ensure that your application is secure, performant, and maintainable.

With this comprehensive guide, you should now have a solid understanding of how to use Axios for HTTP requests in JavaScript. Axios is a powerful library with a lot of features, and by mastering it, you'll be able to handle HTTP requests efficiently and effectively in your applications. Happy coding!