Angular Functional Interceptors using HttpInterceptorFn
January 29, 2024
On this page, we will learn to create functional HTTP interceptors using HttpInterceptorFn
in our Angular standalone application. HTTP interceptors are created using HttpInterceptorFn
and HttpInterceptor
. The withInterceptors()
and withInterceptorsFromDi()
are passed to provideHttpClient()
to configure interceptors.
HttpInterceptorFn : Creates functional interceptor for HTTP requests made via
HttpClient
.
HttpInterceptor : Creates class based interceptors.
provideHttpClient() : Configures
HttpClient
to be available for injection.
withInterceptors() : Adds one or more functional interceptors for
HttpClient
instance.
withInterceptorsFromDi() : Adds one or more class based interceptors.
Here on this page we will learn to create and configure interceptors using
HttpInterceptorFn
.
1. HttpInterceptorFn
HttpInterceptorFn
is a middleware function used to create interceptors. HttpClient
calls these interceptors when HTTP requests are made. These interceptors can modify outgoing request or any response that comes back. They can also block, redirect the request and response as well as can change their semantics.
Find the
HttpInterceptorFn
construct from the Angular doc.
type HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => Observable<HttpEvent<unknown>>;
HttpRequest
to hit.
next : Represents the next interceptor as
HttpHandlerFn
in an interceptor chain.
Now find the simple interceptor that is doing nothing.
import { HttpHandlerFn, HttpInterceptorFn, HttpRequest } from "@angular/common/http"; export const noopInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => { console.log("-- noopInterceptor --"); return next(req); };
HttpClient
instance. In Angular standalone application, HttpClient
is provided using provideHttpClient()
and interceptors are configured using withInterceptors()
as below.
bootstrapApplication(AppComponent, { providers: [ provideHttpClient(withInterceptors([noopInterceptor])) ] });
withInterceptors()
accepts array of functional interceptors and they will execute in the order they have been configured.
We can also write functional interface inline with
withInterceptors()
as below.
providers: [ provideHttpClient(withInterceptors([ (req: HttpRequest<unknown>, next: HttpHandlerFn) => { console.log("-- noopInterceptor --"); return next(req); } ])) ]
2. Creating Functional Interceptors
We have already learnt creating simple functional interceptor and configure them withwithInterceptors()
. Here I will create HTTP interceptors for authentication and logging and then will configure them with withInterceptors()
.
Step-1 :
a. Find the functional interceptor for authentication.
auth-interceptor.ts
import { HttpRequest, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http'; export const authInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => { console.log("-- authInterceptor --"); const authToken = 'AUTH_TOKEN'; const modifiedReq = req.clone({ headers: req.headers.set('Authorization', `Bearer ${authToken}`), }); console.log(modifiedReq.headers.get('Authorization')); return next(modifiedReq); };
logging-interceptor.ts
import { HttpRequest, HttpResponse, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http'; import { tap } from 'rxjs/operators'; export const loggingInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => { console.log("-- loggingInterceptor --"); let isSuccess = ""; return next(req).pipe( tap({ next: event => { if (event instanceof HttpResponse) { isSuccess = "success"; } }, error: () => isSuccess = "fail", finalize: () => console.log("Request ", isSuccess) }) ); }
withInterceptors()
as an array. To configure multiple interceptors, we need to take care their order in array because they will execute in that order.
src/app/app.config.ts
import { ApplicationConfig } from '@angular/core'; import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { loggingInterceptor } from './http-interceptors/logging-interceptor'; import { authInterceptor } from './http-interceptors/auth-interceptor'; export const APP_CONFIG: ApplicationConfig = { providers: [ provideHttpClient(withInterceptors([authInterceptor, loggingInterceptor])), ] };
authInterceptor
is at zero index, hence it will execute before loggingInterceptor
. The output in console will be as below.
-- authInterceptor -- Bearer AUTH_TOKEN -- loggingInterceptor -- Request success
APP_CONFIG
in main.ts.
src/main.ts
import { bootstrapApplication } from '@angular/platform-browser'; import { APP_CONFIG } from './app/app.config'; import { AppComponent } from './app/app.component'; bootstrapApplication(AppComponent, APP_CONFIG) .catch((err) => console.error(err));