DEV Community

Cover image for ⚡ Conditional Interceptors in Angular 20
Xhani Manolis Trungu
Xhani Manolis Trungu

Posted on

⚡ Conditional Interceptors in Angular 20

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
};
Enter fullscreen mode Exit fullscreen mode

👉 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
};
Enter fullscreen mode Exit fullscreen mode

👉 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);
};
Enter fullscreen mode Exit fullscreen mode

👉 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])
    ),
  ],
});
Enter fullscreen mode Exit fullscreen mode

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)