Angular - Http vs HttpClient

Featured

The release of Angular 4.3 saw the introduction of a new Http service - the HttpClient. It comes with a number of changes over the old Http service - in fact it's an upgrade to it with better functionality. In this article we'll review some of the changes.

Angular > 4.3.x

If the Angular version is greater than 4.3 we can use the new HttpClient which has some interesting changes.

First of all in order to import the new HttpClient we need to use a different import statement as it's been moved to a different package making sure that the old Http client can still be used - hence this is a non-breaking change. So to import the HttpClient execute the following statement:

import { HttpClient } from '@angular/common/http';

Please also note that in order to use the HttpClient the HttpClientModule needs to be imported to the application:

// additional imports
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [ ],
  bootstrap: [AppComponent]
})
export class AppModule { }

JSON data returned by default

The new HttpClient by default formats the response to JSON so we no longer need to parse it using response.json():

constructor(private http: HttpClient) {
  this.http.get('http://my.api/data')
      .subscribe(response => console.log(response));
}

In older versions of Angular (< 4.3.x) we had to import the RXJS map method and parse the response as JSON:

// more code
import 'rxjs/add/operator/map';
// more code
constructor(private http: HttpClient) {
  this.http.get('http://my.api/data')
      .map((response: any) => response.json())
      .subscribe(response => console.log(response));
}

This step is no longer required. In fact, if we do this we'll get the TypeError: response.json is not a function. (In 'response.json()', 'response.json' is undefined) message.

Interceptors and middlewares

Interceptors allow us to intercept or mutate HTTP requests and responses. An interceptor is really just a TypeScript class (an injectable service) that implements the HttpInterceptor:

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

@Injectable()
export class MyInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler):  Observable<HttpEvent<any>> {
    request = request.clone({
      setHeaders: {
        'X-Custom-Header': 'Agent-007'
      }
    });
    return next.handle(request);
  }
}

The code above interepts all requests and attaches a new header to them (X-Custom-Header).

Another change in the HttpClient is that both the request and response objects are immutable therefore if we want to modify it we first need to create a copy as seen in the code above as well.

Progress events

The new HttpClient allows for capturing progress events such as the Upload and Download progress events. In order to access such events, the HttpRequest needs to be created manually:

// more code
import { HttpClient, HttpRequest, HttpEvent, HttpEventType } from '@angular/common/http';
// more code
constructor(private http: HttpClient) {
  const request = new HttpRequest('GET', 'http://my.api/data',
                                  {}, { reportProgress: true });
  this.http.request(request)
    .subscribe((event: HttpEvent<any>) => {
      switch (event.type) {
        case HttpEventType.Sent:
          console.log('Request started');
          break;
        case HttpEventType.ResponseHeader:
          console.log('Headers received ->', event.headers);
          break;
        case HttpEventType.DownloadProgress:
          const loaded = Math.round(event.loaded / 1024);
          console.log(`Downloading ${ loaded } kb downloaded`);
          break;
        case HttpEventType.Response:
          console.log('Finished -> ', event.body);
      }
    });
}

Enjoy using the new HttpClient with Angular!