Series

This post is part of the HttpClient API series:

  1. The new Angular HttpClient API
  2. Testing with the Angular HttpClientTesting API

The HttpClient API was introduced in the version 4.3.0. It is an evolution of the existing HTTP API and has it's own package @angular/common/http. This article gives you an overview of the new main features the new client introduces. For the in-depth look under that hood of the HttpClient check out Insider’s guide into interceptors and HttpClient mechanics in Angular.

One of the most notable changes is that now the response object is a JSON by default, so there's no need to parse it anymore. We can do:

// HttpClient
this.http.get('https://api.github.com/users')
  .subscribe(data => console.log(data));

Rather than:

// Http
this.users = this.http.get('https://api.github.com/users')
  .map(response => response.json())
  .subscribe(data => console.log(data));

However if you're still interested in the whole Response object you can observe for it:

// HttpClient
this.http.get('…', { observe: 'response' });

Query parameters

One thing that might not be as intuitive is the way that it handles query parameters. You can't just really pass a Plain Old JavaScript Object (POJO) over and expect it to be assigned as a query parameter of the request like you would with any other option that can be passed to the options object of the GET call.

import { HttpParams } from '@angular/common/http';
const params = new HttpParams().set('q', 'cironunes');
this.http.get('...', { params });

This is a bit verbose. Luckily there's already a pull request in place to enable the usage of object maps for parameters and headers of GET requests.

Type checking responses

Thanks to TypeScript Generics you type HTTP method you’re calling and the response will get be of that same type:

interface LoginResponse {
  accessToken: string;
  accessExpiration: number;
}
this.http.post<LoginResponse>('api/login', {
  login: 'foo',
  password: 'bar'
}).subscribe(data => {
  console.log(data.accessToken, data.accessExpiration);
});

Requesting non-JSON data

Although it’s the most common, sometimes you’ll deal with different sorts of data. This is supported via the responseType property.

this.http.get('...', { responseType: 'text' }); 
responseType?: 'arraybuffer' | 'blob' | 'json' | 'text'

In this case you don’t need to type the response as the reponseType already do the trick.

Interceptors

The most exciting thing of the HttpClient is the introduction of Interceptors which allow middleware logic to be inserted in the pipeline. Let's take a quick look at how it works.

First of all let's create an interceptor. An Interceptor needs to implement the HttpInterceptor interface which is about implementing the intercept method.

interface HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
}

The intercept method receives an HttpRequest and must return an stream of HttpEvent of type HttpResponse. As the Request and Response objects are immutable — which makes it easier to predict and test, we use the clone method to mutate the Response object.

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

export class AuthInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<HttpEventType.Response>> {
    const authReq = req.clone({
      setHeaders: { Authorization: `Bearer authtest` }
    });
    return next.handle(authReq);
  }

}

You register them like that:

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  imports: [],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ]
})
export class AppModule {}

If you want to register many interceptors you can just put more items in the providers array.

providers: [
  { provide: HTTP_INTERCEPTORS, useClass: First, multi: true },
  { provide: HTTP_INTERCEPTORS, useClass: Second, multi: true }
]

Listening for progress

Another very cool feature is that you can subscribe for events like the upload or download progress via reportProgress option. In a file upload example it would be like that:

const req = new HttpRequest('POST', 'upload/file', file, {
  reportProgress: true
});
this.http.request(req)
  .subscribe(event => {
    if (event.type === HttpEventType.UploadProgress) {
      console.log(event.total, event.loaded);
    }
  });

Wrapping up

The HttpClient API is awesome. Besides favouring the most common use cases, it enforces once again the usage of Observables and Immutable objects whenever it makes sense. That makes using it easier and easy to test code that uses it.

What’s next?

I’ll cover testing with the HttpClientTestingModule in the next post. Stay tuned.