—

🚀 Hook: Why Every Angular App Needs an Interceptor

Imagine you’re building a large‑scale Angular application that talks to dozens of backend services. Every request must carry an auth token, log execution time, and gracefully handle errors. Manually adding this logic to each service quickly becomes a nightmare—code duplication, missed edge cases, and a maintenance nightmare.

Enter Angular HTTP interceptors: a powerful, built‑in mechanism that lets you centralize request/response handling, keep your services clean, and boost both security and performance. In this post we’ll demystify interceptors, show you how to create them, and give you actionable patterns you can drop into any Angular project today.

—

1️⃣ What Is an Angular HTTP Interceptor?

An HTTP interceptor is simply a class that implements the `HttpInterceptor` interface from `@angular/common/http`. Angular’s `HttpClient` runs every outgoing request (and incoming response) through a chain of interceptors before the request hits the network or the response reaches your service.

Key benefits

| Benefit | How it helps |
|———|————–|
| Authentication | Append JWT or API keys automatically |
| Logging & Metrics | Capture request duration, URLs, status codes |
| Error handling | Centralize 401/403 redirects, show toast notifications |
| Request transformation | Add query parameters, change headers, or mock data in dev mode |

Because interceptors are registered in the root injector, they work globally—no need to import them in each feature module.

—

2️⃣ Building Your First Interceptor: The Auth Token Injector

Let’s walk through a minimal, production‑ready interceptor that attaches a bearer token to every request.

“`ts
// src/app/interceptors/auth.interceptor.ts
import { Injectable } from ‘@angular/core’;
import {
HttpEvent, HttpHandler, HttpInterceptor, HttpRequest
} from ‘@angular/common/http’;
import { Observable } from ‘rxjs’;
import { AuthService } from ‘../services/auth.service’;

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}

intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
const token = this.auth.getAccessToken();

// Clone the request and add the Authorization header
const authReq = token
? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })
: req;

return next.handle(authReq);
}
}
“`

Actionable tip: Register the interceptor in `app.module.ts` (or a CoreModule) using the multi‑provider pattern:

“`ts
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
“`

Now every `HttpClient` call automatically carries the token—no more repetitive `setHeaders` code.

—

3️⃣ Advanced Patterns: Logging, Caching, and Global Error Handling

a) Logging Interceptor

“`ts
@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler) {
const started = Date.now();
console.log(`→ ${req.method} ${req.urlWithParams}`);

return next.handle(req).pipe(
tap(event => {
if (event.type === HttpEventType.Response) {
const elapsed = Date.now() – started;
console.log(`← ${req.method} ${req.urlWithParams} (${elapsed}ms)`);
}
})
);
}
}
“`

Add this interceptor before the auth interceptor if you want to log the original request URL (without the token).

b) Simple In‑Memory Cache

For GET requests that rarely change, you can store responses in a `Map` and serve them instantly on subsequent calls:

“`ts
private cache = new Map<string, HttpResponse>();

intercept(req: HttpRequest, next: HttpHandler) {
if (req.method !== ‘GET’) return next.handle(req);

const cached = this.cache.get(req.urlWithParams);
if (cached) return of(cached);

return next.handle(req).pipe(
tap(event => {
if (event instanceof HttpResponse) {
this.cache.set(req.urlWithParams, event);
}
})
);
}
“`

c) Global Error Handler

“`ts
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler) {
return next.handle(req).pipe(
catchError(err => {
if (err.status === 401) {
// redirect to login or refresh token
this.auth.logout();
}
// Show a toast, log to Sentry, etc.
this.toast.show(‘An error occurred’, err.message);
return throwError(() => err);
})
);
}
}
“`

By stacking these interceptors—Auth → Cache → Logging → Error—you get a clean, maintainable pipeline that covers most real‑world scenarios.

—

4️⃣ Testing Interceptors Like a Pro

A well‑tested interceptor prevents subtle bugs in production. Use Angular’s `HttpClientTestingModule` and `HttpTestingController`:

“`ts
it(‘should add Authorization header’, () => {
const token = ‘test-token’;
spyOn(authService, ‘getAccessToken’).and.returnValue(token);

http.get(‘/api/data’).subscribe();
const req = httpMock.expectOne(‘/api/data’);
expect(req.request.headers.get(‘Authorization’)).toBe(`Bearer ${token}`);
req.flush({});
});
“`

Pro tip: Write separate unit tests for each interceptor’s responsibility (auth, logging, error) and keep them isolated by providing only the interceptor under test.

—

📌 Conclusion: Key Takeaways

1. Interceptors are global middleware for Angular’s `HttpClient`, perfect for cross‑cutting concerns like auth, logging, caching, and error handling.
2. Implement the `HttpInterceptor` interface and register with `HTTP_INTERCEPTORS` using the `multi: true` flag.
3. Chain multiple interceptors to keep each class focused on a single responsibility—this improves readability and testability.
4. Leverage RxJS operators (`tap`, `catchError`, `finalize`) inside `intercept` to manipulate requests and responses without breaking the observable flow.
5. Unit test each interceptor with `HttpClientTestingModule` to guarantee reliable behavior across environments.

By mastering Angular HTTP interceptors, you’ll dramatically reduce boilerplate, enforce consistent API contracts, and build a more resilient, maintainable front‑end architecture. Ready to refactor those scattered headers and error handlers? Start adding interceptors today and watch your codebase breathe easier. 🚀

Leave a Reply

Your email address will not be published. Required fields are marked *

Upgrade PHP Version without using cPanel setting