Services
Interceptors
Master Angular HTTP Interceptors, covering functional interceptors, request/response transformation, authentication tokens, logging, and error handling.
1. Learning Objectives
In this lesson, you will master Angular HTTP interceptors. By the end of this topic, you will be able to:
- Explain how interceptors sit in the HTTP request/response pipeline.
- Write functional interceptors using the
HttpInterceptorFntype. - Attach authentication tokens to outgoing requests automatically.
- Implement global error handling and logging interceptors.
- Chain multiple interceptors and understand their execution order.
2. Overview
HTTP interceptors are middleware functions that sit between the application's HTTP calls and the server. They can inspect, modify, or replace outgoing requests and incoming responses before they reach the service or component. Interceptors are ideal for cross-cutting concerns like authentication, logging, caching, and global error handling that apply to every HTTP request.
3. Why This Topic Matters
Interceptors eliminate repetitive cross-cutting code:
- Token Duplication: Without interceptors, every service method must manually attach the authorization header to its HTTP request. This leads to duplicated code across dozens of API calls. An auth interceptor attaches the token in one place for all requests.
- Request Immutability: HTTP request objects in Angular are immutable. A common mistake is trying to modify the original request directly (e.g.,
req.headers.set()). You must clone the request with the modifications usingreq.clone().
4. Real-World Analogy
Think of HTTP interceptors like **security checkpoints at an international airport**:
- Outgoing Request (Departure): Before your luggage (request) leaves the country, it passes through customs. The officer stamps your passport (attaches an auth token) and scans your bags (logs the request details).
- Incoming Response (Arrival): When a package (response) arrives from abroad, it passes through immigration. The officer checks for prohibited items (error handling) and records the arrival (logging).
- Chained Checkpoints (Multiple Interceptors): Your luggage passes through multiple checkpoints in sequence: passport control, customs, and security screening. Each checkpoint inspects the luggage and passes it to the next one in order.
5. Core Concepts
Angular interceptors follow a pipeline architecture:
- HttpInterceptorFn: A function that receives an
HttpRequestand aHttpHandlerFn(the next handler in the chain). It must return anObservable<HttpEvent>. - Request Cloning: Since requests are immutable, interceptors must use
req.clone()to create a modified copy before passing it to the next handler. - Chaining: Multiple interceptors execute in the order they are registered. The request passes through each interceptor sequentially before reaching the server. Responses travel back through the chain in reverse order.
| Interceptor Use Case | Modifies Request | Modifies Response |
|---|---|---|
| Auth Token | Yes (adds Authorization header) | No |
| Logging | No (reads only) | No (reads only) |
| Error Handling | No | Yes (catches and transforms errors) |
| Caching | No | Yes (returns cached response if available) |
6. Syntax & API Reference
Below is a functional authentication interceptor that attaches a Bearer token to all outgoing requests:
Registering Interceptors
7. Visual Diagram
This diagram displays the interceptor pipeline for outgoing requests and incoming responses:
8. Live Example — Full Working Code
Below is a logging interceptor that measures request duration and a global error handler interceptor:
Retry Interceptor Example
9. Interactive Playground
Try It Yourself Challenges:
- Create a caching interceptor that stores GET responses and returns the cached version for repeated requests to the same URL.
- Reverse the order of the auth and logging interceptors and observe how the logged request differs (with vs without the auth token header).
10. Common Mistakes
| Mistake | Why it happens | Wrong | Correct |
|---|---|---|---|
| Modifying the original request directly | Attempting to set headers on the original request object. HTTP requests are immutable in Angular. | req.headers.set('Auth', token); return next(req); |
const cloned = req.clone({ setHeaders: { Auth: token } }); return next(cloned); |
| Forgetting to call next(req) | Not calling next(req) in the interceptor, which stops the request pipeline entirely. No request reaches the server. |
return of(null); // Request never sent |
return next(req); // Pass to next handler |
11. Best Practices
- Always clone requests: Use
req.clone()to create modified copies of immutable request objects. Never attempt to modify the original. - Keep interceptors focused: Each interceptor should handle one concern (auth, logging, or error handling). Avoid combining multiple responsibilities in a single interceptor.
- Order interceptors intentionally: The order in the
withInterceptors()array matters. Place auth interceptors before logging interceptors so that logged requests include auth headers. - Skip interceptors for specific requests: Use request URL checks or custom headers to conditionally skip interceptor logic for specific endpoints (e.g., do not attach auth tokens to public API calls).
12. Browser Compatibility/Requirements
Interceptors run within the Angular HttpClient pipeline and have no browser-specific requirements. They work consistently across all modern browsers and in server-side rendering environments.
13. Interview Questions
Q1: Why must you clone HTTP requests in interceptors instead of modifying them directly?
Answer: Angular's HttpRequest objects are immutable by design. This immutability ensures that the original request remains unchanged for retries, logging, and other interceptors in the chain. You must call req.clone() with the desired modifications to create a new request object.
Q2: In what order do interceptors execute for requests and responses?
Answer: For outgoing requests, interceptors execute in the order they are registered in the withInterceptors() array (first to last). For incoming responses, they execute in reverse order (last to first), since the response travels back through the chain.
14. Debugging Exercise
The auth interceptor is supposed to attach a Bearer token, but API requests still return 401 Unauthorized. Identify the bug:
Diagnosis: The interceptor attempts to call req.headers.set() on the original request object. Since Angular HTTP requests are immutable, this call returns a new HttpHeaders instance but does not modify the original request. The unmodified request is passed to next() without the Authorization header.
Fix: Use req.clone() to create a new request with the added header.
15. Practice Exercises
Exercise 1: Build a loading spinner interceptor
Create an interceptor that increments a counter in a shared LoadingService when a request starts and decrements it when the request completes or errors. Build a loading bar component that shows a spinner whenever the counter is greater than zero.
16. Scenario-Based Challenge
The Token Refresh Interceptor Challenge:
When a 401 Unauthorized response is received, the interceptor should call a token refresh endpoint to get a new access token, update the stored token in the AuthService, clone the original failed request with the new token, and retry it. If the refresh also fails, redirect the user to the login page.
17. Quick Quiz
Q1: Which method must you use to modify an HTTP request inside an interceptor?
A) req.headers.set()
B) req.clone()
C) req.update()
Answer: B — Use req.clone() to create a modified copy of the immutable request object.
18. Summary & Key Takeaways
- Interceptors are middleware functions that transform HTTP requests and responses globally.
- Always use
req.clone()to modify requests since they are immutable. - Register interceptors using
withInterceptors()inprovideHttpClient(). - Interceptor execution order matches the registration array order for requests, and reverses for responses.
- Keep each interceptor focused on a single responsibility (auth, logging, error handling).
19. Cheat Sheet
| API | Purpose |
|---|---|
HttpInterceptorFn |
Type for functional interceptor functions. |
req.clone({ setHeaders: {} }) |
Creates a modified copy of an immutable request. |
withInterceptors([...]) |
Registers interceptors with provideHttpClient. |
next(req) |
Passes the request to the next handler in the chain. |