Intercept HTTP Requests in Angular and Ionic 2

Angular has an impressive dependency injection system, however some aspects could be documented better. Old blog posts explaining how things worked before the final release don't help either. Hence, it took me a while to successfully intercept HTTP requests and inject a common parameter.

The HTTP requests can be intercepted by injecting your own implementation of BaseRequestOptions class:

import { BaseRequestOptions, RequestOptionsArgs, RequestOptions, URLSearchParams } from '@angular/http';

export class AppRequestOptions extends BaseRequestOptions {

  merge(options?: RequestOptionsArgs): RequestOptions {
    let newOptions = super.merge(options);
    // params is not instantiated if original request has no parameters
    newOptions.params = newOptions.params || new URLSearchParams();
    // params was introduced in Angular 4 / Ionic 3
    // in Angular 2 / Ionic 2 use search instead
    newOptions.params.set('api_key', '234jhf35brhf3f7fv3v78f39');
    return newOptions;
  }
}

In the above snippet I add an api_key parameter to every request but I could also add headers or change other aspects of the request.

To actually inject this implementation, add the following entry to the providers array of NgModule declaration:

@NgModule({
  // ...
  providers: [
    // ...
    {provide: RequestOptions, useClass: AppRequestOptions}
  ]
})

You can inject other providers in your BaseRequestOptions implementations as well:

export class Configuration {
  apiKey = '234jhf35brhf3f7fv3v78f39';
}

@Injectable()
export class AppRequestOptions extends BaseRequestOptions {

  constructor(private config: Configuration) {
    super();
  }

  merge(options?: RequestOptionsArgs): RequestOptions {
    let newOptions = super.merge(options);
    newOptions.params = newOptions.params || new URLSearchParams();
    newOptions.search.set('api_key', this.config.apiKey);
    return newOptions;
  }
}

For this to work, you need to add the Injectable decorator to your class or you'll get the following not so helpful error:

Can't resolve all parameters for AppRequestOptions: (?)

Also don't forget to include Configuration to NgModule's providers array:

@NgModule({
  // ...
  providers: [
    // ...
    {provide: RequestOptions, useClass: AppRequestOptions},
    Configuration
  ]
})
Copyright
Creative Commons License