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 underlyingfetch()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 (like404or500). A Fetch middleware must explicitly checkresponse.okorresponse.statusto 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.