Using Async/Await Within an Angular Interceptor

Async/Await is great, it makes the code much more readable and clean. It is, however, quite tricky to use it within an Angular interceptor. This is how you do it.


Angular interceptors with async/await

I like working with promises, and interceptors (and Angular) usually use observables. Async/await also makes promises so much easier to read and maintain, so that’s why I prefer working with it. It’s, however, a bit complicated to set up and work with, this is one way you can accomplish it.

Scroll to the bottom for a TL;DR.

Full example

Like most other Angular function, we will use an RxJS operator called from, which turns a promise into an observable.

Let’s say this is our base interceptor.

import { HttpInterceptor} from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class ExampleInterceptor implements HttpInterceptor {
   intercept(request: HttpRequest<any>, next: HttpHandler):   Observable<HttpEvent<any>> {
       // ...
   }
}

In this example, we will try to catch a 401 error, and handle that asynchronously with async/await. For this, we will also use the catchError operator from RxJS.

return next.handle(request).pipe(catchError(error => {
    if (error instanceof HttpErrorResponse && error.status === 401) {
        // ...
	}
}))

The most important logic, the one which lets us use promises. We need to create a new asynchronous method and call it with the from operator.

from(this.handle401Error(request, next));

The function might look something like this.

private async handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    const newRequest = await this.someService.asyncChange(request);
    return next.handle(newRequest).toPromise(); 
}

We need to use the toPromise() function to turn it into a promise, which the from operator will turn back to an observable.

This is the final code.

import { HttpInterceptor} from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable()
export class ExampleInterceptor implements HttpInterceptor {
   intercept(request: HttpRequest<any>, next: HttpHandler):   Observable<HttpEvent<any>> {

        return next.handle(request).pipe(catchError(error => {

            if (error instanceof HttpErrorResponse && error.status === 401) {
                from(this.handle401Error(request, next));
            }
        }))
   }

    private async handle401Error(request: HttpRequest<any>, next: HttpHandler) {
        const newRequest = await await this.someService.asyncChange(request);
        return next.handle(newRequest).toPromise(); 
    }
}

TL;DR

The code above might look a bit cluttered. The most important parts are these two:

if (error instanceof HttpErrorResponse && error.status === 401) {
    from(this.handle401Error(request, next));
}
private async handle401Error(request: HttpRequest<any>, next: HttpHandler) {
    const newRequest = await await this.someService.asyncChange(request);
    return next.handle(newRequest).toPromise(); 
}