Using the Fetch API with Interceptors and Error Handling
Jul 26, 2025 am 08:15 AMAlthough the Fetch API does not have built-in interceptors and global error handling, it can be implemented through encapsulation functions; 2. In a custom apiClient, request interception can add authentication headers and default configurations before sending, and response interception can handle response data or errors uniformly; 3. By parsing the response status and content type, common HTTP errors are converted into standardized error objects and thrown; 4. Integrate logging, timeout control (using AbortController) and global error listening (such as unhandledrejection events); 5. Finally, a robust and maintainable HTTP client written in one time and reused multiple times does not need to rely on Axios.
When working with the Fetch API in JavaScript, you quickly realize it doesn't include built-in support for request/response interceptors or centralized error handling like Axios does. But with a little abstraction, you can add these features to make your HTTP calls more maintained and robust.

Here's how to enhance the Fetch API with interceptors and error handling in a clean, reusable way.
? Create a Custom Fetch Wrapper
Instead of calling fetch()
directly, wrap it in a function that allows you to:

- Intercept requests (eg, add auth headers)
- Intercept responses (eg, log, transform, or handle errors)
- Handle common HTTP errors globally
const apiClient = async (endpoint, options = {}) => { const defaultHeaders = { 'Content-Type': 'application/json', }; // ? Request Interceptor: Modify request before sending const config = { ...options, headers: { ...defaultHeaders, ...options.headers, }, }; // Add auth token if available const token = localStorage.getItem('authToken'); if (token) { config.headers['Authorization'] = `Bearer ${token}`; } const baseUrl = 'https://api.example.com'; const response = await fetch(`${baseUrl}${endpoint}`, config); // ? Response Interceptor: Handle responses and errors if (!response.ok) { let errorMessage = `HTTP Error: ${response.status}`; let errorData; const contentType = response.headers.get('content-type'); if (contentType && contentType.includes('application/json')) { errorData = await response.json(); errorMessage = errorData.message || errorMessage; } else { errorData = await response.text(); } // Throw a standardized error object throw new Error(JSON.stringify({ status: response.status, message: errorMessage, data: errorData, })); } // Parse JSON only if response has content const contentType = response.headers.get('content-type'); if (contentType && contentType.includes('application/json')) { return await response.json(); } return await response.text(); };
? Add Interceptor-Like Behavior
Since fetch
doesn't support interceptors natively, you simulate them inside your wrapper:
- Request Interception : Modify options before
fetch
is called - Response Interception : Process or transform responses before returning
You can even make it more modular:

// Optional: Add logging interceptor const logRequest = (url, options) => { console.log(`[API] Request: ${url}`, options); }; const logResponse = (url, data) => { console.log(`[API] Response from ${url}:`, data); }; // Update your apiClient to use them const apiClient = async (endpoint, options = {}) => { const baseUrl = 'https://api.example.com'; const url = `${baseUrl}${endpoint}`; logRequest(url, options); // ? Request interceptor // ... (rest of the logic) const data = await (response.json ? response.json() : response.text()); logResponse(url, data); // ? Response interceptor return data; };
? Centralized Error Handling
Instead of handling errors in every .catch()
or try/catch
, handle them consistently:
// Usage with try/catch try { const user = await apiClient('/user/123'); console.log(user); } catch (error) { const { status, message, data } = JSON.parse(error.message); if (status === 401) { // Redirect to login window.location.href = '/login'; } else if (status === 404) { console.warn('Resource not found'); } else { console.error('API Error:', message); } }
Or use a global error handler for non-recoverable cases:
window.addEventListener('unhandledrejection', (event) => { const error = JSON.parse(event.reason.message); if (error.status >= 500) { alert('We're having server issues. Please try again later.'); } });
? Optional: Add Request Timeout
fetch
doesn't time out by default. You can add one using AbortController
:
const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s try { const response = await fetch(url, { ...config, signal: controller.signal, }); clearTimeout(timeoutId); return response; } catch (err) { if (err.name === 'AbortError') { throw new Error('Request timed out'); } throw err; }
? Summary
While the Fetch API is lightweight and modern, it lacks convenience features like interceptors and automatic error parsing. By wrapping it:
- ? You get request/response interference
- ? Global error handling and status checks
- ? Consistent headers , auth, and timeouts
- ? Better UX and debugging
You don't need Axios to have a powerful HTTP client — just a thin, smart wrapper.
Basically, write once, reuse everywhere.
The above is the detailed content of Using the Fetch API with Interceptors and Error Handling. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

In C++, exception handling handles errors gracefully through try-catch blocks. Common exception types include runtime errors, logic errors, and out-of-bounds errors. Take file opening error handling as an example. When the program fails to open a file, it will throw an exception and print the error message and return the error code through the catch block, thereby handling the error without terminating the program. Exception handling provides advantages such as centralization of error handling, error propagation, and code robustness.

In Go function unit testing, there are two main strategies for error handling: 1. Represent the error as a specific value of the error type, which is used to assert the expected value; 2. Use channels to pass errors to the test function, which is suitable for testing concurrent code. In a practical case, the error value strategy is used to ensure that the function returns 0 for negative input.

In Go functions, asynchronous error handling uses error channels to asynchronously pass errors from goroutines. The specific steps are as follows: Create an error channel. Start a goroutine to perform operations and send errors asynchronously. Use a select statement to receive errors from the channel. Handle errors asynchronously, such as printing or logging error messages. This approach improves the performance and scalability of concurrent code because error handling does not block the calling thread and execution can be canceled.

There are two ways to handle errors gracefully in Go: The defer statement is used to execute code before the function returns, usually to release resources or log errors. The recover statement is used to catch panics in functions and allow the program to handle errors in a more graceful manner instead of crashing.

In Golang, error wrappers allow you to create new errors by appending contextual information to the original error. This can be used to unify the types of errors thrown by different libraries or components, simplifying debugging and error handling. The steps are as follows: Use the errors.Wrap function to wrap the original errors into new errors. The new error contains contextual information from the original error. Use fmt.Printf to output wrapped errors, providing more context and actionability. When handling different types of errors, use the errors.Wrap function to unify the error types.

The best error handling tools and libraries in PHP include: Built-in methods: set_error_handler() and error_get_last() Third-party toolkits: Whoops (debugging and error formatting) Third-party services: Sentry (error reporting and monitoring) Third-party libraries: PHP-error-handler (custom error logging and stack traces) and Monolog (error logging handler)

Error handling and logging in C++ class design include: Exception handling: catching and handling exceptions, using custom exception classes to provide specific error information. Error code: Use an integer or enumeration to represent the error condition and return it in the return value. Assertion: Verify pre- and post-conditions, and throw an exception if they are not met. C++ library logging: basic logging using std::cerr and std::clog. External logging libraries: Integrate third-party libraries for advanced features such as level filtering and log file rotation. Custom log class: Create your own log class, abstract the underlying mechanism, and provide a common interface to record different levels of information.

GoLang functions can perform error internationalization through the Wrapf and Errorf functions in the errors package, thereby creating localized error messages and appending them to other errors to form higher-level errors. By using the Wrapf function, you can internationalize low-level errors and append custom messages, such as "Error opening file %s".
