Chapter 7.3โ˜• 15 min read

Interceptors

Interceptors sit between your component and the server, letting you modify requests before they go out and responses before they reach your code.

01What is an Interceptor

An interceptor sits BETWEEN your HTTP call and the server. It can:

  • Modify the request BEFORE it goes out (add auth token, add base URL, log)
  • Modify the response BEFORE it reaches your component (handle errors, transform data)
  • Act on every HTTP request automatically โ€” no changes needed in individual services

"Interceptor = post office โ€” tum letter likho, post office stamp laga ke, address check karke bhejta hai."

Common use cases:

  • Add Authorization token to every request
  • Add base URL prefix
  • Log all HTTP requests and responses
  • Handle 401 errors globally โ€” redirect to login
  • Show/hide loading spinner on request start/end
  • Add request timing for performance monitoring

Interceptors work like middleware in Express.js or Django โ€” every request passes through them like a pipeline.

02Functional Interceptor (New Way)

Functional interceptors are the new way (Angular 15+). They are simple functions instead of classes.

// auth.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from './auth.service';

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const authService = inject(AuthService);
  const token = authService.getToken();

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

  // Pass the cloned request to the next handler
  return next(authReq);
};

"Functional = lambda function โ€” simple, clean, no class."

Registration:

// app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './interceptors/auth.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withInterceptors([authInterceptor])
    ),
  ]
};

req.clone() is important โ€” you NEVER mutate the original request. You clone it and modify the clone. This prevents bugs in other interceptors.

03Common Interceptor Use Cases

Here are the most common interceptor use cases with real code:

1. Auth โ€” Add Bearer Token

export const authInterceptor: HttpInterceptorFn = (req, next) => {
  const token = inject(AuthService).getToken();
  return next(req.clone({
    setHeaders: { Authorization: `Bearer ${token}` }
  }));
};

2. Logging โ€” Log Every Request

export const loggingInterceptor: HttpInterceptorFn = (req, next) => {
  const start = performance.now();
  console.log(`[HTTP] ${req.method} ${req.url}`);
  return next(req).pipe(
    tap(() => console.log(`[HTTP] ${req.url} took ${performance.now() - start}ms`))
  );
};

3. Base URL โ€” Prepend API URL

export const baseUrlInterceptor: HttpInterceptorFn = (req, next) => {
  if (!req.url.startsWith('http')) {
    return next(req.clone({
      url: `https://api.hyderabad.com${req.url}`
    }));
  }
  return next(req);
};

4. Error Handling โ€” Catch 401 Globally

export const errorInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req).pipe(
    catchError(error => {
      if (error.status === 401) {
        inject(Router).navigate(['/login']);
      }
      return throwError(() => error);
    })
  );
};

"Interceptors = middleware โ€” har request ke saath automatically kaam karo."

04Chaining Multiple Interceptors

You can chain multiple interceptors โ€” each one runs in sequence.

// app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { loggingInterceptor } from './interceptors/logging.interceptor';
import { authInterceptor } from './interceptors/auth.interceptor';
import { errorInterceptor } from './interceptors/error.interceptor';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withInterceptors([
        loggingInterceptor,  // 1st โ€” logs request
        authInterceptor,     // 2nd โ€” adds token
        errorInterceptor     // 3rd โ€” handles errors
      ])
    ),
  ]
};

Order matters! Here's how the pipeline works:

// REQUEST direction (first in array = first to run):
logging โ†’ auth โ†’ error โ†’ (server)

// RESPONSE direction (LAST in array = first to run):
error โ†’ auth โ†’ logging โ†’ (component)

"Pipeline = factory assembly line โ€” ek ke baad ek."

For requests: the first interceptor in the array runs first. For responses: the last interceptor in the array runs first (because of how RxJS pipes work โ€” the response flows backwards through the pipeline).

05Modifying Response in Interceptor

Interceptors can also modify responses using RxJS operators in the pipe().

export const responseInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req).pipe(
    // Log the response
    tap(event => {
      if (event.type === HttpEventType.Response) {
        console.log('Response received:', event.status);
      }
    }),

    // Handle errors
    catchError(error => {
      if (error.status === 401) {
        // Token expired โ€” redirect to login
        inject(Router).navigate(['/login']);
      }
      if (error.status === 0) {
        // Network error
        console.error('Network error โ€” check your connection');
      }
      // Re-throw the error so component still gets it
      return throwError(() => error);
    })
  );
};

"Request modify karo ya response modify karo โ€” dono possible."

  • tap() โ€” side effect (logging, analytics) without changing the value
  • catchError() โ€” handle errors globally
  • map() โ€” transform the response data
  • retry() โ€” retry failed requests

You can use ANY RxJS operator inside an interceptor's pipe.

Key Takeaways

  • โœ… Interceptors sit between component and server โ€” modify requests/responses globally
  • โœ… Functional interceptors (HttpInterceptorFn) are the new way โ€” simple functions, no classes
  • โœ… Always clone with req.clone() โ€” never mutate the original request object
  • โœ… Chaining: first in array runs first for request, last runs first for response
  • โœ… Common use cases: auth token, logging, base URL, error handling, loading spinner
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase