Axios Interceptors vs Fetch API Middleware

Axios interceptors and Fetch API middleware are two different approaches to manipulating HTTP requests and responses in JavaScript applications. While Axios provides a native, promise-based interceptor system out of the box, the standard Fetch API does not support native interceptors, requiring developers to implement middleware patterns via custom wrapper functions or third-party abstractions. This article explores how both mechanisms operate, their architectural differences, and when to use each approach.

Native Support and Implementation

Axios Interceptors are built directly into the library. You can attach request or response interceptors globally to the base Axios instance or to custom instances created with axios.create().

  • Request Interceptors: Execute before the request is sent over the network. They are commonly used for appending authorization tokens, logging, or setting default headers.
  • Response Interceptors: Execute before the response promise is resolved or rejected in application code. They are typically used for global error handling, data transformation, or automatic token refreshing.
// Axios Request Interceptor
axios.interceptors.request.use((config) => {
  config.headers.Authorization = `Bearer ${token}`;
  return config;
});

Fetch API Middleware is not a native browser feature. The standard window.fetch() function is a low-level API that accepts a URL and an options object, returning a promise. To achieve interceptor-like behavior with Fetch, developers must wrap the fetch function using higher-order functions, class-based clients, or libraries like Ky or Redux-inspired pipelines.

// Fetch Wrapper / Middleware Pattern
const customFetch = async (url, options = {}) => {
  // Pre-request logic (Request Middleware)
  options.headers = {
    ...options.headers,
    Authorization: `Bearer ${token}`
  };

  const response = await fetch(url, options);

  // Post-request logic (Response Middleware)
  if (!response.ok) {
    // Handle errors globally
  }

  return response;
};

Execution Architecture: Chains vs. Pipelines

The architectural pattern used to execute logic differs significantly between the two:

  • Axios (Promise Chains): Axios maintains two separate arrays: one for request interceptors and one for response interceptors. Interceptors are executed sequentially in the order they are defined. Request interceptors process the config object, the network call executes, and response interceptors process the resulting data or error.
  • Fetch Middleware ("Onion" Pipeline): Fetch middleware is often implemented using a composition or "onion" model (similar to Express or Koa). A single middleware function can handle both the request and response phases by controlling when next() or the underlying fetch() call is triggered.

Error Handling

  • Axios: Rejection handlers in Axios interceptors catch both network failures and non-2xx HTTP status codes automatically. If a server returns a 401 Unauthorized, the response error interceptor catches it immediately, making centralized token refresh flows straightforward to implement.
  • Fetch: The native fetch() promise only rejects on actual network failures, not on HTTP error statuses (like 404 or 500). A Fetch middleware must explicitly check response.ok or response.status to trigger error-handling logic before forwarding the result.

Comparison Summary

Feature Axios Interceptors Fetch API Middleware
Native Support Built-in Requires custom wrapper or library
Execution Flow Distinct Request/Response queues Composed wrapper / Pipeline pattern
HTTP Error Handling Automatically triggers error interceptors for 4xx/5xx Requires manual response.ok check
Cancellation/Ejection Built-in eject() method Requires custom unsubscribe logic
Bundle Size Impact Adds external dependency size Minimal (using native fetch)

Conclusion

The primary difference lies in convenience versus flexibility. Axios interceptors provide a standardized, ready-to-use solution for intercepting network traffic with minimal boilerplate. Conversely, Fetch middleware requires custom architectural setup but offers complete control over the execution pipeline without adding external library overhead.