> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/angular/angular/llms.txt
> Use this file to discover all available pages before exploring further.

# HttpInterceptor

> API reference for intercepting and transforming HTTP requests and responses in Angular

HTTP interceptors allow you to intercept and transform HTTP requests and responses globally in your Angular application. They're useful for adding authentication tokens, logging, error handling, caching, and more.

## Interface Definition

```typescript theme={null}
interface HttpInterceptor {
  intercept(
    req: HttpRequest<any>, 
    next: HttpHandler
  ): Observable<HttpEvent<any>>;
}
```

## Functional Interceptor

Angular also provides a functional approach with `HttpInterceptorFn`:

```typescript theme={null}
type HttpInterceptorFn = (
  req: HttpRequest<unknown>,
  next: HttpHandlerFn
) => Observable<HttpEvent<unknown>>;
```

## Importing

<CodeGroup>
  ```typescript Class-based theme={null}
  import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
  import { Injectable } from '@angular/core';

  @Injectable()
  export class AuthInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler) {
      // Interceptor logic
      return next.handle(req);
    }
  }
  ```

  ```typescript Functional theme={null}
  import { HttpInterceptorFn } from '@angular/common/http';

  export const authInterceptor: HttpInterceptorFn = (req, next) => {
    // Interceptor logic
    return next(req);
  };
  ```
</CodeGroup>

## Methods

### intercept()

Intercepts an HTTP request and handles it.

<ParamField path="req" type="HttpRequest<any>" required>
  The outgoing request object to handle
</ParamField>

<ParamField path="next" type="HttpHandler | HttpHandlerFn" required>
  The next interceptor in the chain, or the backend if no interceptors remain
</ParamField>

<ResponseField name="return" type="Observable<HttpEvent<any>>">
  An observable of the HTTP event stream
</ResponseField>

## Usage Examples

### Functional Interceptor (Recommended)

The functional approach is more lightweight and works with Angular's injection context:

<CodeGroup>
  ```typescript Authentication Token theme={null}
  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();
    
    if (token) {
      const cloned = req.clone({
        headers: req.headers.set('Authorization', `Bearer ${token}`)
      });
      return next(cloned);
    }
    
    return next(req);
  };
  ```

  ```typescript Logging theme={null}
  import { HttpInterceptorFn, HttpEventType } from '@angular/common/http';
  import { tap } from 'rxjs/operators';

  export const loggingInterceptor: HttpInterceptorFn = (req, next) => {
    console.log('Request:', req.method, req.url);
    const startTime = Date.now();
    
    return next(req).pipe(
      tap(event => {
        if (event.type === HttpEventType.Response) {
          const elapsed = Date.now() - startTime;
          console.log(`Response: ${req.url} took ${elapsed}ms`);
        }
      })
    );
  };
  ```

  ```typescript Error Handling theme={null}
  import { HttpInterceptorFn } from '@angular/common/http';
  import { catchError } from 'rxjs/operators';
  import { throwError } from 'rxjs';
  import { inject } from '@angular/core';
  import { ErrorService } from './error.service';

  export const errorInterceptor: HttpInterceptorFn = (req, next) => {
    const errorService = inject(ErrorService);
    
    return next(req).pipe(
      catchError(error => {
        errorService.logError(error);
        return throwError(() => error);
      })
    );
  };
  ```

  ```typescript Retry Logic theme={null}
  import { HttpInterceptorFn } from '@angular/common/http';
  import { retry } from 'rxjs/operators';

  export const retryInterceptor: HttpInterceptorFn = (req, next) => {
    return next(req).pipe(
      retry({
        count: 3,
        delay: 1000
      })
    );
  };
  ```

  ```typescript Caching theme={null}
  import { HttpInterceptorFn, HttpResponse } from '@angular/common/http';
  import { of } from 'rxjs';
  import { tap } from 'rxjs/operators';
  import { inject } from '@angular/core';
  import { CacheService } from './cache.service';

  export const cacheInterceptor: HttpInterceptorFn = (req, next) => {
    if (req.method !== 'GET') {
      return next(req);
    }
    
    const cache = inject(CacheService);
    const cached = cache.get(req.url);
    
    if (cached) {
      return of(cached);
    }
    
    return next(req).pipe(
      tap(event => {
        if (event instanceof HttpResponse) {
          cache.set(req.url, event);
        }
      })
    );
  };
  ```
</CodeGroup>

### Class-based Interceptor (Legacy)

The traditional class-based approach:

<CodeGroup>
  ```typescript Authentication theme={null}
  import { Injectable } from '@angular/core';
  import { 
    HttpInterceptor, 
    HttpRequest, 
    HttpHandler,
    HttpEvent 
  } from '@angular/common/http';
  import { Observable } from 'rxjs';

  @Injectable()
  export class AuthInterceptor implements HttpInterceptor {
    constructor(private authService: AuthService) {}
    
    intercept(
      req: HttpRequest<any>, 
      next: HttpHandler
    ): Observable<HttpEvent<any>> {
      const token = this.authService.getToken();
      
      if (token) {
        const cloned = req.clone({
          headers: req.headers.set('Authorization', `Bearer ${token}`)
        });
        return next.handle(cloned);
      }
      
      return next.handle(req);
    }
  }
  ```

  ```typescript Loading Indicator theme={null}
  import { Injectable } from '@angular/core';
  import { 
    HttpInterceptor, 
    HttpRequest, 
    HttpHandler 
  } from '@angular/common/http';
  import { finalize } from 'rxjs/operators';

  @Injectable()
  export class LoadingInterceptor implements HttpInterceptor {
    constructor(private loadingService: LoadingService) {}
    
    intercept(req: HttpRequest<any>, next: HttpHandler) {
      this.loadingService.show();
      
      return next.handle(req).pipe(
        finalize(() => this.loadingService.hide())
      );
    }
  }
  ```
</CodeGroup>

## Providing Interceptors

### Functional Interceptors

Use `withInterceptors()` to provide functional interceptors:

```typescript theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './auth.interceptor';
import { loggingInterceptor } from './logging.interceptor';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(
      withInterceptors([authInterceptor, loggingInterceptor])
    )
  ]
});
```

### Class-based Interceptors

Use `HTTP_INTERCEPTORS` token to provide class-based interceptors:

```typescript theme={null}
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ]
})
export class AppModule {}
```

Or with standalone APIs:

```typescript theme={null}
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { HTTP_INTERCEPTORS } from '@angular/common/http';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(withInterceptorsFromDi()),
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ]
});
```

## Interceptor Chain

Interceptors are called in the order they are provided:

```typescript theme={null}
provideHttpClient(
  withInterceptors([
    authInterceptor,      // Called first
    loggingInterceptor,   // Called second
    retryInterceptor,     // Called third
    cacheInterceptor      // Called last
  ])
)
```

<Note>
  Each interceptor must call `next()` to pass the request to the next interceptor. If an interceptor doesn't call `next()`, the request chain is broken and the request won't reach the server.
</Note>

## Request Transformation

Requests are immutable, so you must clone them to make changes:

```typescript theme={null}
export const modifyHeadersInterceptor: HttpInterceptorFn = (req, next) => {
  // Clone the request and modify headers
  const modified = req.clone({
    headers: req.headers
      .set('X-Custom-Header', 'value')
      .set('Accept', 'application/json')
  });
  
  return next(modified);
};
```

### Common Transformations

<CodeGroup>
  ```typescript Add Headers theme={null}
  const cloned = req.clone({
    headers: req.headers.set('X-API-Key', 'abc123')
  });
  ```

  ```typescript Modify URL theme={null}
  const cloned = req.clone({
    url: req.url.replace('http://', 'https://')
  });
  ```

  ```typescript Add Parameters theme={null}
  const cloned = req.clone({
    params: req.params.set('api_version', 'v2')
  });
  ```

  ```typescript Set Credentials theme={null}
  const cloned = req.clone({
    withCredentials: true
  });
  ```

  ```typescript Modify Body theme={null}
  const cloned = req.clone({
    body: { ...req.body, timestamp: Date.now() }
  });
  ```
</CodeGroup>

## Response Transformation

Transform responses using RxJS operators:

```typescript theme={null}
import { map } from 'rxjs/operators';
import { HttpResponse } from '@angular/common/http';

export const transformResponseInterceptor: HttpInterceptorFn = (req, next) => {
  return next(req).pipe(
    map(event => {
      if (event instanceof HttpResponse) {
        // Transform the response body
        return event.clone({
          body: {
            data: event.body,
            timestamp: Date.now()
          }
        });
      }
      return event;
    })
  );
};
```

## Conditional Interception

Apply interception logic conditionally:

```typescript theme={null}
export const conditionalInterceptor: HttpInterceptorFn = (req, next) => {
  // Only intercept API calls
  if (req.url.startsWith('/api/')) {
    const modified = req.clone({
      headers: req.headers.set('X-API-Key', 'abc123')
    });
    return next(modified);
  }
  
  // Pass through without modification
  return next(req);
};
```

## Error Handling

Handle errors at the interceptor level:

```typescript theme={null}
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { Router } from '@angular/router';
import { inject } from '@angular/core';

export const authErrorInterceptor: HttpInterceptorFn = (req, next) => {
  const router = inject(Router);
  
  return next(req).pipe(
    catchError(error => {
      if (error.status === 401) {
        // Redirect to login on unauthorized
        router.navigate(['/login']);
      }
      return throwError(() => error);
    })
  );
};
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use Functional Interceptors">
    Prefer functional interceptors (`HttpInterceptorFn`) over class-based interceptors for better tree-shaking and simpler code.
  </Accordion>

  <Accordion title="Keep Interceptors Focused">
    Each interceptor should have a single responsibility. Create multiple interceptors rather than one complex interceptor.
  </Accordion>

  <Accordion title="Always Call next()">
    Always call `next()` (functional) or `next.handle()` (class-based) unless you intentionally want to block the request.
  </Accordion>

  <Accordion title="Clone Before Modifying">
    Requests are immutable. Always clone the request before modifying it.
  </Accordion>

  <Accordion title="Handle Errors Gracefully">
    Use proper error handling to prevent the interceptor chain from breaking.
  </Accordion>

  <Accordion title="Be Aware of Order">
    Interceptors execute in the order they're provided. Order matters for operations like authentication and logging.
  </Accordion>
</AccordionGroup>

## Common Use Cases

<CardGroup cols={2}>
  <Card title="Authentication" icon="key">
    Add authentication tokens to outgoing requests
  </Card>

  <Card title="Logging" icon="file-text">
    Log all HTTP requests and responses
  </Card>

  <Card title="Error Handling" icon="alert-triangle">
    Centralized error handling and recovery
  </Card>

  <Card title="Loading States" icon="loader">
    Show/hide loading indicators
  </Card>

  <Card title="Caching" icon="database">
    Cache responses for improved performance
  </Card>

  <Card title="Retry Logic" icon="rotate-cw">
    Automatically retry failed requests
  </Card>

  <Card title="Request Transformation" icon="edit">
    Modify requests before sending
  </Card>

  <Card title="Response Transformation" icon="filter">
    Transform responses before consumption
  </Card>
</CardGroup>

## See Also

<CardGroup cols={2}>
  <Card title="HTTP Overview" icon="book" href="/api/http/overview">
    Introduction to Angular's HTTP client
  </Card>

  <Card title="HttpClient" icon="code" href="/api/http/http-client">
    Complete API reference for HttpClient
  </Card>
</CardGroup>

## Related Types

* [HttpRequest](https://angular.dev/api/common/http/HttpRequest) - Represents an HTTP request
* [HttpResponse](https://angular.dev/api/common/http/HttpResponse) - Represents an HTTP response
* [HttpHandler](https://angular.dev/api/common/http/HttpHandler) - Interface for the next handler
* [HttpEvent](https://angular.dev/api/common/http/HttpEvent) - Union type for HTTP events
* [HttpErrorResponse](https://angular.dev/api/common/http/HttpErrorResponse) - Represents an HTTP error
