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)