If you’ve been working with Angular long enough, you’ve probably met HTTP interceptors. They’re like little bouncers standing at the door of every HTTP request:
Need an auth token? 👉 They’ll attach it.
Want to log everything? 👉 They’ll spam your console.
Craving retries and caching? 👉 They’ll hook you up.
But here’s the catch: not all requests need retries or caching.
🔑 A login request should never retry automatically (unless you really want to lock yourself out after 3 failed attempts).
📊 An analytics API probably doesn’t need caching (who cares how many clicks you had yesterday?).
🛒 A product catalog API? That’s a perfect candidate for retries and caching — because your users expect snappy results when browsing products.
This is where conditional interceptors shine. Instead of blindly applying logic everywhere, we tell Angular:
👉 “Only do this for specific APIs. Don’t waste my time elsewhere.”
🎯 The Goal
Here’s what we’re aiming for:
✅ Apply retry logic only to specific APIs.
✅ Cache results from APIs that benefit from re-use.
✅ Keep the pipeline clean by skipping unnecessary logic.
Sounds good? Let’s code.
💡 Retry Interceptor (Conditional)
Retries are great for flaky networks — but disastrous for sensitive endpoints like login. Let’s apply retries only to our catalog API.
import { HttpInterceptorFn } from '@angular/common/http';
import { retry } from 'rxjs';
export const retryInterceptor: HttpInterceptorFn = (req, next) => {
const shouldRetry = req.url.includes('/api/catalog');
if (shouldRetry) {
return next(req).pipe(
retry(3) // 🔄 retry failed requests up to 3 times
);
}
return next(req); // 🚫 no retry for other endpoints
};
👉 Here we only retry /api/catalog requests. Login, auth, and other APIs are left untouched (your account is safe 🎉).
💡 Simple Caching Interceptor (Conditional)
Nobody likes waiting for the same data twice. Let’s add a simple in-memory cache, again only for /api/catalog.
import { HttpInterceptorFn } from '@angular/common/http';
import { of, tap } from 'rxjs';
const cache = new Map<string, any>();
export const cachingInterceptor: HttpInterceptorFn = (req, next) => {
const isCacheable = req.method === 'GET' && req.url.includes('/api/catalog');
if (isCacheable) {
const cachedResponse = cache.get(req.url);
if (cachedResponse) {
console.log('📦 Returning cached response for', req.url);
return of(cachedResponse); // ✅ serve from cache
}
return next(req).pipe(
tap((event) => {
cache.set(req.url, event); // 💾 store in cache
})
);
}
return next(req); // 🚫 no caching for other requests
};
👉 This way, repeated GET /api/catalog/... requests are blazing fast. Other endpoints? Business as usual.
⚙️ Conditional Composition
Now let’s combine caching + retry into a single conditional interceptor.
import { HttpInterceptorFn } from '@angular/common/http';
import { cachingInterceptor } from './caching.interceptor';
import { retryInterceptor } from './retry.interceptor';
export const conditionalApiInterceptor: HttpInterceptorFn = (req, next) => {
const isCatalogApi = req.url.includes('/api/catalog');
if (isCatalogApi) {
// 🌀 Compose caching + retry
return cachingInterceptor(req, (cachedReq) =>
retryInterceptor(cachedReq, next)
);
}
// 🚫 Fallback: no special logic
return next(req);
};
👉 Magic!
Catalog requests get both caching & retry.
Other requests cruise straight through untouched.
🔌 Registering the Interceptors
Finally, let’s wire everything up in Angular 20.
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { AppComponent } from './app/app.component';
import { conditionalApiInterceptor } from './app/interceptors/conditional-api.interceptor';
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(
withInterceptors([conditionalApiInterceptor])
),
],
});
That’s it. Your app now has context-aware retries and caching. 🎉
🚀 Benefits
Granular control – retries/caching only where they’re safe.
Performance boost – no more wasted network calls.
Cleaner code – no bloated if statements everywhere.
🔮 Real-World Use Cases
✅ Retry catalog/product listing APIs but never login requests.
✅ Cache user profile data for smoother navigation.
✅ Apply special logic only in production (keep dev logs noisy).
📝 Takeaway
Conditional interceptors in Angular 20 make your HTTP pipeline smart, fast, and drama-free. Instead of spamming all requests with retries or caching, you only enhance the ones that truly matter.
This pattern keeps your code clean, reliable, and ready to scale.
⚡ Bonus: You can even pair this with feature flags to toggle retries/caching at runtime — no redeploys needed.
Top comments (0)