Axios - Documentation

What is Axios?

Axios is a popular, promise-based HTTP client for making asynchronous requests to REST endpoints and other HTTP servers. It’s designed to work in both browser and Node.js environments, offering a consistent API across platforms. It simplifies the process of sending HTTP requests (GET, POST, PUT, DELETE, etc.) and handling their responses, including error handling. Axios intercepts requests and responses, allowing for modifications before they are sent or after they are received. This makes it ideal for tasks like adding authentication headers, transforming data, or handling common errors.

Why use Axios?

Axios offers several advantages over other HTTP client libraries and native approaches:

Axios vs. Fetch API

While both Axios and the native Fetch API are used for making HTTP requests, Axios offers several advantages:

Setting up Axios

Setting up Axios is straightforward. For browser environments, include the library via a <script> tag or use a module bundler like Webpack. For Node.js, install it using npm or yarn:

Node.js:

npm install axios

or

yarn add axios

Browser (using a CDN):

Add this script tag to your HTML file:

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

Import in your JavaScript code (both browser and Node.js with module bundler):

import axios from 'axios';

After installation or inclusion, you can start making requests using the Axios API. Refer to the subsequent sections for details on making different types of requests and utilizing Axios features.

Making Requests

GET requests

GET requests retrieve data from a specified resource. Here’s how to make a GET request with Axios:

axios.get('/user?ID=12345')
  .then(response => {
    console.log(response.data); // Access the response data
  })
  .catch(error => {
    console.error(error); // Handle errors
  });

This example fetches data from /user?ID=12345. The response data is accessible via response.data.

POST requests

POST requests submit data to be processed to a specified resource. This is often used to create new resources.

axios.post('/user', {
    firstName: 'John',
    lastName: 'Doe',
    age: 30
  })
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This sends a JSON payload to /user. The response contains the result of the POST operation.

PUT requests

PUT requests replace all current representations of the target resource with the request payload.

axios.put('/user/12345', {
    firstName: 'Jane',
    lastName: 'Doe',
    age: 25
  })
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This updates the resource at /user/12345 with the provided data.

PATCH requests

PATCH requests apply partial modifications to a resource. Only the specified fields are updated.

axios.patch('/user/12345', {
    age: 26
  })
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This updates only the age field of the resource at /user/12345.

DELETE requests

DELETE requests delete the specified resource.

axios.delete('/user/12345')
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This deletes the resource at /user/12345.

Request parameters

Request parameters are added to the URL query string.

axios.get('/users', {
  params: {
    page: 1,
    limit: 10
  }
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This results in a request to /users?page=1&limit=10.

Request headers

Request headers provide additional information about the request.

axios.get('/users', {
  headers: {
    'Authorization': 'Bearer my-token',
    'Content-Type': 'application/json'
  }
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This adds authorization and content type headers to the request.

Request body (data)

The request body contains data sent with POST, PUT, and PATCH requests.

axios.post('/users', {
  firstName: 'Bob',
  lastName: 'Smith'
}, {
  headers: {
    'Content-Type': 'application/json' //Important for JSON payloads
  }
})
.then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

This sends a JSON object as the request body. Ensure the correct Content-Type header is set.

Handling different response types

Axios automatically parses JSON responses. For other types, handle them accordingly:

axios.get('/data')
  .then(response => {
    if (response.headers['content-type'].includes('application/json')) {
      console.log('JSON response:', response.data);
    } else if (response.headers['content-type'].includes('text/plain')) {
      console.log('Plain text response:', response.data);
    } else {
      console.log('Other response type:', response.data);
    }
  })
  .catch(error => {
    console.error(error);
  });

Timeout settings

Set a timeout for requests to prevent indefinite hanging.

axios.get('/slow-resource', {
  timeout: 5000 // 5 seconds
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    if (error.code === 'ECONNABORTED') {
      console.error('Request timed out');
    } else {
      console.error(error);
    }
  });

Interceptors

Interceptors allow modifying requests and responses globally.

axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    config.headers.Authorization = 'Bearer my-new-token';
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response;
  }, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
  });

This example adds an authorization header to all outgoing requests and handles response errors globally. Remember to handle potential errors appropriately within interceptors.

Handling Responses

Status Codes

Axios responses include a status property indicating the HTTP status code. You should always check the status code to ensure the request was successful. Codes in the 2xx range generally indicate success, while others (e.g., 4xx client errors, 5xx server errors) signal issues.

axios.get('/users')
  .then(response => {
    if (response.status === 200) {
      console.log('Success:', response.data);
    } else if (response.status === 404) {
      console.error('Not Found');
    } else {
      console.error('Error:', response.status);
    }
  })
  .catch(error => {
    console.error('Request failed:', error);
  });

This example checks for a 200 OK status and handles a 404 Not Found error specifically.

Response Data

The response data is accessible via the response.data property. The format depends on the Content-Type header of the response. Axios automatically parses JSON responses into JavaScript objects. For other content types (e.g., text/plain, text/html), response.data will contain the raw response body as a string.

axios.get('/api/data')
  .then(response => {
    console.log(response.data); // Access the JSON data
    console.log(typeof response.data); //Should output 'object' for JSON
  })
  .catch(error => {
    console.error(error);
  });

Response Headers

Response headers provide additional information about the response. They are accessible via response.headers.

axios.get('/api/data')
  .then(response => {
    console.log(response.headers); //Access all headers
    console.log(response.headers['content-type']); //Access specific header
    console.log(response.headers['content-length']);//Access specific header
  })
  .catch(error => {
    console.error(error);
  });

Error Handling

Axios uses promises, so errors are handled using .catch(). The error object contains information about the error, including the response (if available) and the error code.

axios.get('/invalid-endpoint')
  .then(response => {
    console.log(response.data);
  })
  .catch(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.error('Response Error:', error.response.data);
      console.error('Status:', error.response.status);
      console.error('Headers:', error.response.headers);
    } else if (error.request) {
      // 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.error('Request Error:', error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.error('Error:', error.message);
    }
    console.error('Config:', error.config);
  });

This comprehensive error handling checks for different error scenarios: network errors (no response), server errors (non-2xx status codes), and other errors during request setup.

Transforming Responses

You can transform responses using interceptors or within the .then() block. This is useful for modifying data before it’s used in your application.

axios.get('/api/data')
  .then(response => {
    const transformedData = response.data.map(item => ({
      id: item.id,
      name: item.name.toUpperCase()
    }));
    console.log(transformedData);
  })
  .catch(error => {
    console.error(error);
  });

This example transforms the response data by converting names to uppercase. More complex transformations can be implemented here or using response interceptors for global transformations.

Advanced Usage

Cancellation of requests

Axios allows you to cancel pending requests using a CancelToken. This is useful for preventing unnecessary requests when, for instance, a user navigates away from a page before a request completes.

import axios from 'axios';
const CancelToken = axios.CancelToken;
let cancel;

const fetchData = () => {
  cancel && cancel(); // Cancel any previous request
  axios.get('/data', {
    cancelToken: new CancelToken(function executor(c) {
      cancel = c;
    })
  })
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    if (axios.isCancel(error)) {
      console.log('Request cancelled', error.message);
    } else {
      console.error(error);
    }
  });
};

//Call fetchData multiple times to demonstrate cancellation
fetchData();
setTimeout(fetchData, 2000); //Simulate a second request after 2 seconds
setTimeout(() => cancel(), 1500); //Cancel after 1.5 seconds

This example shows how to create a CancelToken and use it to cancel a request. The axios.isCancel function helps differentiate between cancellation and other errors.

Authentication

Authentication is typically handled by including authorization headers in your requests. The specific method depends on your authentication scheme (e.g., Bearer tokens, Basic Auth).

// Bearer Token Authentication
axios.get('/protected-resource', {
  headers: {
    Authorization: `Bearer ${localStorage.getItem('token')}`
  }
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });


//Basic Auth (generally less secure, avoid if possible)
axios.get('/protected-resource', {
  auth: {
    username: 'user',
    password: 'password'
  }
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

Uploading Files

To upload files, use FormData and set the Content-Type header appropriately.

const formData = new FormData();
formData.append('file', fileInput.files[0]); //fileInput is a file input element

axios.post('/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  }
})
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    console.error(error);
  });

Downloading Files

Downloading files often involves setting the responseType to 'blob' and handling the response appropriately.

axios({
  url: '/download',
  method: 'GET',
  responseType: 'blob',
})
  .then(response => {
    const url = window.URL.createObjectURL(new Blob([response.data]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'filename.ext'); // Set filename
    document.body.appendChild(link);
    link.click();
  })
  .catch(error => {
    console.error(error);
  });

Proxies

If you need to use a proxy, you can configure it in your Axios instance.

const axiosInstance = axios.create({
  proxy: {
    host: 'your-proxy-host',
    port: your-proxy-port
  }
});

axiosInstance.get('/data')
  .then(...)
  .catch(...);

Customizing Axios Instance

Create customized Axios instances for specific needs (e.g., different base URLs, headers).

const api = axios.create({
  baseURL: 'https://api.example.com',
  headers: {
    'X-Custom-Header': 'value'
  }
});

api.get('/users')
  .then(...)
  .catch(...);

Working with JSON Data

Axios automatically parses JSON responses. Ensure your server sends the correct Content-Type header (application/json).

axios.get('/api/users')
  .then(response => {
    const users = response.data; // users is a JavaScript object/array
    console.log(users);
  })
  .catch(error => {
    console.error(error);
  });

Working with FormData

Use FormData for sending files or other non-JSON data. Remember the multipart/form-data content type. (See Uploading Files above)

Using Axios with React

Axios works well within React applications. Typically, you’d make requests within component functions or custom hooks.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    axios.get('/api/data')
      .then(response => setData(response.data))
      .catch(error => console.error(error));
  }, []);

  return (
    <div>
      {/* ... render data ... */}
    </div>
  );
}

Using Axios with other frameworks

Axios is framework-agnostic and works similarly in other JavaScript frameworks (Vue, Angular, Svelte, etc.). The integration patterns are similar to the React example above.

Debugging Tips

Security Considerations

Cross-Origin Resource Sharing (CORS)

Cross-Origin Resource Sharing (CORS) is a mechanism that allows web pages from one origin (domain, protocol, and port) to access resources from a different origin. Axios, by default, handles CORS automatically. However, if your requests are blocked due to CORS issues, you need to configure your backend server to allow requests from your frontend origin. This typically involves setting appropriate headers on the server-side (e.g., Access-Control-Allow-Origin).

If you encounter CORS errors, check your browser’s developer console for error messages detailing the CORS issue. Ensure your server is correctly configured to allow requests from the origin of your frontend application. For example, if your frontend runs on https://example.com and your backend API is on https://api.example.com, https://api.example.com needs to be configured to allow requests from https://example.com.

Important Note: Using Access-Control-Allow-Origin: * is generally discouraged in production environments as it allows any origin to access your API, creating a significant security vulnerability. Instead, specify the exact origins allowed.

Protecting against XSS attacks

Cross-Site Scripting (XSS) attacks occur when malicious scripts are injected into otherwise benign and trusted websites. Axios itself does not directly prevent XSS attacks; preventing them requires server-side measures and secure coding practices on the frontend. Here’s how to mitigate XSS vulnerabilities related to Axios:

Handling Sensitive Data

When working with sensitive data (passwords, credit card information, API keys, etc.) using Axios, it is crucial to take extra precautions:

Appendix

Glossary of Terms

Changelog

(This section would contain a chronologically ordered list of significant changes and updates to Axios. Include version numbers, release dates, and a brief description of the changes. For example:)

v1.5.0 (YYYY-MM-DD): * Added support for new feature X. * Fixed bug Y. * Improved performance of Z.

v1.4.0 (YYYY-MM-DD): * Introduced breaking change A. * Enhanced security feature B.

v1.3.1 (YYYY-MM-DD): * Minor bug fix.

(Continue adding entries for each version)

(Note: Replace the placeholder version numbers and dates with actual release information from the Axios project.)