NexusCS

Axios

JavaScript
Axios: promise-based HTTP client for browser and Node.js with interceptors and automatic JSON.
featured

Getting started

Installation

# Package managers
npm install axios
yarn add axios
pnpm add axios
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

Import

// ES6
import axios from "axios";

// CommonJS
const axios = require("axios");

Quick example

// GET request
const { data } = await axios.get("/users");

// POST request
await axios.post("/users", {
  name: "John",
  email: "john@example.com",
});

Basic requests

HTTP methods

// GET
const { data } = await axios.get("/users");

// POST
await axios.post("/users", {
  name: "John",
  email: "john@example.com",
});

// PUT
await axios.put("/users/1", {
  name: "Updated",
});

// PATCH
await axios.patch("/users/1", {
  email: "new@email.com",
});

// DELETE
await axios.delete("/users/1");

Full config syntax

await axios({
  method: "post",
  url: "/users",
  data: { name: "John" },
});

Response destructuring

// Get only data
const { data } = await axios.get("/users");

// Get status and headers
const { status, headers, data } = await axios.get("/users");

Request config

Config options

axios({
  method: "post", // HTTP method
  url: "/user/12345", // Request URL
  baseURL: "https://api.example.com",
  headers: {
    Authorization: "Bearer token",
    "Content-Type": "application/json",
  },
  params: { ID: 12345 }, // URL parameters
  data: { firstName: "Fred" }, // Request body
  timeout: 1000, // Milliseconds
  withCredentials: false, // Send cookies
  responseType: "json", // Response type
  maxRedirects: 5, // Max redirects
  validateStatus: (status) => status < 500,
});

Common options

Option Description Default
baseURL Base URL prefix -
headers Request headers {}
params URL query params -
data Request body -
timeout Request timeout (ms) 0
withCredentials Send cookies false
responseType Response format 'json'
validateStatus Status validator status >= 200 && status < 300

Response types

responseType: "arraybuffer"; // ArrayBuffer
responseType: "document"; // DOM document
responseType: "json"; // JSON (default)
responseType: "text"; // String
responseType: "stream"; // Node.js stream
responseType: "blob"; // Blob

Response schema

Response object

{
  data: {},          // Response body
  status: 200,       // HTTP status code
  statusText: 'OK',  // Status message
  headers: {},       // Response headers (lowercase)
  config: {},        // Original request config
  request: {}        // XMLHttpRequest / http.ClientRequest
}

Headers are always lowercase:

response.headers["content-type"]; // Correct
response.headers["Content-Type"]; // Won't work

Creating instances

Custom instance

const api = axios.create({
  baseURL: "https://api.example.com",
  timeout: 1000,
  headers: { "X-Custom-Header": "foobar" },
});

// Use like axios
api.get("/user/12345");

Instance defaults

const api = axios.create({
  baseURL: "https://api.example.com",
});

// Update defaults
api.defaults.headers.common["Authorization"] = AUTH_TOKEN;
api.defaults.timeout = 2500;

Config precedence

// 1. Library defaults (lowest priority)
axios.defaults.timeout = 1000;

// 2. Instance defaults
const api = axios.create({ timeout: 2000 });

// 3. Request config (highest priority)
api.get("/users", { timeout: 3000 });

Interceptors

Request interceptor

axios.interceptors.request.use(
  (config) => {
    // Modify config before request
    config.headers.Authorization = "Bearer " + getToken();
    return config;
  },
  (error) => {
    // Handle request error
    return Promise.reject(error);
  },
);

Response interceptor

axios.interceptors.response.use(
  (response) => {
    // Process successful response
    return response;
  },
  (error) => {
    // Handle response error
    if (error.response?.status === 401) {
      // Redirect to login
    }
    return Promise.reject(error);
  },
);

Remove interceptor

// Store interceptor ID
const id = axios.interceptors.request.use(fn);

// Remove later
axios.interceptors.request.eject(id);

Instance interceptors

const api = axios.create();

api.interceptors.request.use((config) => {
  // Only affects this instance
  return config;
});

Error handling

Error types

try {
  await axios.get("/user/12345");
} catch (error) {
  if (error.response) {
    // Server responded with non-2xx
    console.log(error.response.status);
    console.log(error.response.data);
    console.log(error.response.headers);
  } else if (error.request) {
    // No response received
    console.log(error.request);
  } else {
    // Request setup error
    console.log(error.message);
  }
}

Type guard

if (axios.isAxiosError(error)) {
  // TypeScript: error is AxiosError
  console.log(error.response?.status);
  console.log(error.code);
}

Serialize error

const errorJson = error.toJSON();
// Returns serializable error object

Custom status validation

axios.get("/user", {
  validateStatus: (status) => {
    // Accept 404 as success
    return status < 500;
  },
});

Authentication

Bearer token (global)

axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;

Per request

axios.get("/user", {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

Basic auth

axios.get("/user", {
  auth: {
    username: "jane",
    password: "s3cret",
  },
});

Cookies cross-origin

axios.get("https://api.example.com/data", {
  withCredentials: true,
});

Cancellation

AbortController

const controller = new AbortController();

axios.get("/user/12345", {
  signal: controller.signal,
});

// Cancel request
controller.abort();

Timeout via AbortSignal

// Auto-cancel after 5 seconds
axios.get("/user", {
  signal: AbortSignal.timeout(5000),
});

CancelToken is deprecated (v0.22.0+). Use AbortController instead.

FormData & file uploads

FormData upload

const formData = new FormData();
formData.append("file", fileInput.files[0]);
formData.append("name", "Document");

axios.post("/upload", formData);

Shorthand syntax

// Automatically creates FormData
axios.postForm("/upload", {
  file: fileInput.files[0],
  name: "Document",
});

Progress tracking

axios.post("/upload", formData, {
  onUploadProgress: (progressEvent) => {
    const percentCompleted = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total,
    );
    console.log(`${percentCompleted}%`);
  },
});

Download progress

axios.get("/file.zip", {
  onDownloadProgress: (progressEvent) => {
    const percentCompleted = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total,
    );
  },
});

Concurrent requests

Promise.all

const [users, permissions] = await Promise.all([
  axios.get("/users"),
  axios.get("/permissions"),
]);

console.log(users.data);
console.log(permissions.data);

Promise.allSettled

const results = await Promise.allSettled([
  axios.get("/users"),
  axios.get("/permissions"),
]);

results.forEach((result) => {
  if (result.status === "fulfilled") {
    console.log(result.value.data);
  } else {
    console.log(result.reason);
  }
});

TypeScript

Type response data

import axios, { AxiosResponse } from "axios";

interface User {
  id: number;
  name: string;
}

// Typed response
const { data } = await axios.get<User>("/user/1");
console.log(data.name); // TypeScript knows this is a string

Error type guard

import { AxiosError } from "axios";

try {
  await axios.get("/user");
} catch (error) {
  if (axios.isAxiosError(error)) {
    const axiosError: AxiosError = error;
    console.log(axiosError.response?.status);
    console.log(axiosError.code);
  }
}

Custom instance type

import axios, { AxiosInstance } from "axios";

const api: AxiosInstance = axios.create({
  baseURL: "https://api.example.com",
});

Generic response type

interface ApiResponse<T> {
  success: boolean;
  data: T;
}

const response = await axios.get<ApiResponse<User>>("/user/1");
console.log(response.data.data.name);

Config defaults

Global defaults

// Base URL for all requests
axios.defaults.baseURL = "https://api.example.com";

// Common headers
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;

// POST headers
axios.defaults.headers.post["Content-Type"] =
  "application/x-www-form-urlencoded";

Precedence: library defaults < instance defaults < request config

Gotchas

Common pitfalls

  • ⚠️ Global defaults affect ALL instances — Use axios.create() for isolated config
  • ⚠️ timeout only covers response, not connection — Combine with AbortController for full timeout control
  • ⚠️ CancelToken is deprecated (v0.22.0+) — Use AbortController instead
  • ⚠️ Response headers are always lowercase — Use response.headers['content-type'], not 'Content-Type'
  • ⚠️ validateStatus default only accepts 2xx — Override for custom status handling
  • ⚠️ statusText may be empty in HTTP/2 — Don't rely on it for error messages
  • ⚠️ null/undefined params are silently ignored — Use empty string if needed in query string

Also see