Default and specific request timeout

It appears that without extending HttpClientModule classes, the only expected ways for interceptors to communicate with respective requests are params and headers objects.

Since timeout value is scalar, it can be safely provided as a custom header to the interceptor, where it can be decided if it’s default or specific timeout that should be applied via RxJS timeout operator:

import { Inject, Injectable, InjectionToken } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { timeout } from 'rxjs/operators';

export const DEFAULT_TIMEOUT = new InjectionToken<number>('defaultTimeout');

@Injectable()
export class TimeoutInterceptor implements HttpInterceptor {
  constructor(@Inject(DEFAULT_TIMEOUT) protected defaultTimeout: number) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const timeoutValue = req.headers.get('timeout') || this.defaultTimeout;
    const timeoutValueNumeric = Number(timeoutValue);

    return next.handle(req).pipe(timeout(timeoutValueNumeric));
  }
}

This can be configured in your app module like:

providers: [
  [{ provide: HTTP_INTERCEPTORS, useClass: TimeoutInterceptor, multi: true }],
  [{ provide: DEFAULT_TIMEOUT, useValue: 30000 }]
],

The request is then done with a custom timeout header

http.get('/your/url/here', { headers: new HttpHeaders({ timeout: `${20000}` }) });

Since headers are supposed to be strings, the timeout value should be converted to a string first.

Here is a demo.

Credits go to @RahulSingh and @Jota.Toledo for suggesting the idea of using interceptors with timeout.

Leave a Comment