Search code examples
angularangular2-httpangular2-providers

Angular 2 - Using "multi" provider to override Http


I want to override Http with a custom class, say HttpClient to do some operations before a request and after a response, however I don't want to have to remember to import that class instead of the platform http class.

I've been experimenting with doing this via the 'multi' providers, but I can't quite make it click.

Here's my override class:

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';

@Injectable()
export class HttpClient {
  private http: Http;

  constructor(http: Http) {
    this.http = http;
  }

  get(url) {
    let headers = new Headers();
    doSomethingToHeader(headers);
    return this.http.get(url, {
      headers: headers
    });
  }
}

And here's my main.ts

bootstrap(AppComponent, [
  provide(HTTP_PROVIDERS, {useExisting: HTTP_PROVIDERS, multi: true}),
  provide(HTTP_PROVIDERS, {useClass: HttpClient, multi: true})
]);

But when I try to call http.get() in my app, I get

ORIGINAL EXCEPTION: No provider for Http!

Any ideas? Am I going about this the wrong way?

Thanks!

UPDATE

I found this blog post. It pretty much describes what Gunter describes below. I'm accepting his answer.


Solution

  • multi: true only works when the provider is designed to be a multi provider like PLATFORM_DIRECTIVES. HTTP_PROVIDERS are not multi providers, it's just a collection of individual providers.

    What you can do is

    bootstrap(AppComponent, [HTTP_PROVIDERS, {provide: Http, useClass: HttpClient}])
    

    results in cycles (see comments)

    This should work:

    bootstrap(AppComponent, [
      HTTP_PROVIDERS, 
      {
        provide: Http, 
        useFactory: (backend, defaultOptions) => new HttpClient(new Http(backend, defaultOptions)),
        deps: [XHRBackend, RequestOptions]
      }
    ])
    

    The important part is that your custom provider that overrides the provider defined in HTTP_PROVIDERS comes after the one you want to override. Therefore it's important that HTTP_PROVIDERS comes before {provide: Http, ...}

    With multi: true you don't override a provider but instead add another item to a provider that provides a set of values.