233

Which one to use to build a mock web service to test the Angular 4 app?

Alexander Abakumov
  • 10,817
  • 10
  • 71
  • 111
Aiyoub
  • 4,703
  • 6
  • 22
  • 34
  • 7
    [*"HttpClient is an evolution of the existing Angular HTTP API, which exists alongside of it in a separate package..."*](https://github.com/angular/angular/commit/37797e2). – jonrsharpe Jul 16 '17 at 14:47
  • 1
    I actually wrote about some of its new features on my blog yesterday: http://blog.jonrshar.pe/2017/Jul/15/angular-http-client.html – jonrsharpe Jul 16 '17 at 14:53
  • 4
    https://angular.io/guide/http – yurzui Jul 16 '17 at 14:55
  • 7
    The tutorial uses HttpModule and https://angular.io/guide/http uses HttpClientModule and neither explains when one or the other should be used or what version of Angular is needed to use what. – Mickey Segal Sep 19 '17 at 15:29
  • Check this Angular 8 HttpClient Example to consume RESTFul API https://www.freakyjolly.com/angular-7-8-httpclient-service-tutorial-to-consume-restfull-api-from-server/ – Code Spy Aug 07 '19 at 15:42

5 Answers5

343

Use the HttpClient class from HttpClientModule if you're using Angular 4.3.x and above:

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

@NgModule({
 imports: [
   BrowserModule,
   HttpClientModule
 ],
 ...

 class MyService() {
    constructor(http: HttpClient) {...}

It's an upgraded version of http from @angular/http module with the following improvements:

  • Interceptors allow middleware logic to be inserted into the pipeline
  • Immutable request/response objects
  • Progress events for both request upload and response download

You can read about how it works in Insider’s guide into interceptors and HttpClient mechanics in Angular.

  • Typed, synchronous response body access, including support for JSON body types
  • JSON is an assumed default and no longer needs to be explicitly parsed
  • Post-request verification & flush based testing framework

Going forward the old http client will be deprecated. Here are the links to the commit message and the official docs.

Also pay attention that old http was injected using Http class token instead of the new HttpClient:

import { HttpModule } from '@angular/http';

@NgModule({
 imports: [
   BrowserModule,
   HttpModule
 ],
 ...

 class MyService() {
    constructor(http: Http) {...}

Also, new HttpClient seem to require tslib in runtime, so you have to install it npm i tslib and update system.config.js if you're using SystemJS:

map: {
     ...
    'tslib': 'npm:tslib/tslib.js',

And you need to add another mapping if you use SystemJS:

'@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
Max Koretskyi
  • 85,840
  • 48
  • 270
  • 414
  • 1
    I am trying to import HttpClientModule. But '@angular/common/http' is not present in node_modules directory which I installed using "npm start" command. Can you help? – Dheeraj Kumar Jul 27 '17 at 07:27
  • 1
    @DheerajKumar, which version are you using? it's only available in 4.3.0 and up – Max Koretskyi Jul 27 '17 at 07:31
  • I downloaded angular quick start from git. and In package.json, "@angular/common": "^4.3.0" is present. but there is no @angular/common/http. – Dheeraj Kumar Jul 27 '17 at 07:35
  • remove `node_modules` folder and run `npm install` again – Max Koretskyi Jul 27 '17 at 07:44
  • @Maxiums. npm install fails with error. Can you guide me where can I get fresh version of angular 4.3?? – Dheeraj Kumar Jul 27 '17 at 08:04
  • @DheerajKumar, if you're just learning Angular, you can use [this setup](https://github.com/maximusk/angular-seed). Otherwise you may be better off with using AngularCLI – Max Koretskyi Jul 27 '17 at 08:12
  • I tried your code. Browser wont startup on np_start. When I goto localhost:\3000. It doesnt load appComponene.t, just index.html. I dont know why its so hard to get a 4.3 angular working :( – Dheeraj Kumar Jul 27 '17 at 09:16
  • @DheerajKumar, can you create a separate question maybe? The community might help – Max Koretskyi Jul 27 '17 at 09:35
  • 5
    I've run into this very same issue (I am using System.js). One thing that is missing from this answer is that you'll also need to map the new module in system.js as follows: `'@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',` – Tyler O Aug 08 '17 at 18:02
  • I'm trying to set up an app built with the tour of heroes tutorial to use HttpClient. I've set everything up properly as far as I can tell, but when I attempt to run the simplest possible unit test, I get an error stating that tslib is missing. It's not. And I'm pointing to it in systemjs as shown above... – Tad Donaghe Oct 02 '17 at 23:24
  • I upgrated to v7.2.15 and still i can use HttpModule but don't forget that angular recommends to use HttpClientModule. – Must.Tek Oct 24 '19 at 13:45
44

Don't want to be repetitive, but just to summarize in other way (features added in new HttpClient):

  • Automatic conversion from JSON to an object
  • Response type definition
  • Event firing
  • Simplified syntax for headers
  • Interceptors

I wrote an article, where I covered the difference between old "http" and new "HttpClient". The goal was to explain it in the easiest way possible.

Simply about new HttpClient in Angular

skryvets
  • 2,102
  • 24
  • 28
18

This is a good reference, it helped me switch my http requests to httpClient.

It compares the two in terms of differences and gives code examples.

This is just a few differences I dealt with while changing services to httpclient in my project (borrowing from the article I mentioned) :

Importing

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

Requesting and parsing response:

@angular/http

 this.http.get(url)
      // Extract the data in HTTP Response (parsing)
      .map((response: Response) => response.json() as GithubUser)
      .subscribe((data: GithubUser) => {
        // Display the result
        console.log('TJ user data', data);
      });

@angular/common/http

 this.http.get(url)
      .subscribe((data: GithubUser) => {
        // Data extraction from the HTTP response is already done
        // Display the result
        console.log('TJ user data', data);
      });

Note: You no longer have to extract the returned data explicitly; by default, if the data you get back is type of JSON, then you don't have to do anything extra.

But, if you need to parse any other type of response like text or blob, then make sure you add the responseType in the request. Like so:

Making the GET HTTP request with responseType option:

 this.http.get(url, {responseType: 'blob'})
      .subscribe((data) => {
        // Data extraction from the HTTP response is already done
        // Display the result
        console.log('TJ user data', data);
      });

Adding Interceptor

I also used interceptors for adding the token for my authorization to every request, reference.

like so:

@Injectable()
export class MyFirstInterceptor implements HttpInterceptor {

    constructor(private currentUserService: CurrentUserService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        // get the token from a service
        const token: string = this.currentUserService.token;

        // add it if we have one
        if (token) {
            req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + token) });
        }

        // if this is a login-request the header is 
        // already set to x/www/formurl/encoded. 
        // so if we already have a content-type, do not 
        // set it, but if we don't have one, set it to 
        // default --> json
        if (!req.headers.has('Content-Type')) {
            req = req.clone({ headers: req.headers.set('Content-Type', 'application/json') });
        }

        // setting the accept header
        req = req.clone({ headers: req.headers.set('Accept', 'application/json') });
        return next.handle(req);
    }
}

Its a pretty nice upgrade!

peinearydevelopment
  • 8,782
  • 5
  • 36
  • 65
abann sunny
  • 561
  • 6
  • 13
1

There is a library which allows you to use HttpClient with strongly-typed callbacks.

The data and the error are available directly via these callbacks.

A reason for existing

When you use HttpClient with Observable, you have to use .subscribe(x=>...) in the rest of your code.

This is because Observable<HttpResponse<T>> is tied to HttpResponse.

This tightly couples the http layer with the rest of your code.

This library encapsulates the .subscribe(x => ...) part and exposes only the data and error through your Models.

With strongly-typed callbacks, you only have to deal with your Models in the rest of your code.

The library is called angular-extended-http-client.

angular-extended-http-client library on GitHub

angular-extended-http-client library on NPM

Very easy to use.

Sample usage

The strongly-typed callbacks are

Success:

  • IObservable<T>
  • IObservableHttpResponse
  • IObservableHttpCustomResponse<T>

Failure:

  • IObservableError<TError>
  • IObservableHttpError
  • IObservableHttpCustomError<TError>

Add package to your project and in your app module

import { HttpClientExtModule } from 'angular-extended-http-client';

and in the @NgModule imports

  imports: [
    .
    .
    .
    HttpClientExtModule
  ],

Your Models

//Normal response returned by the API.
export class RacingResponse {
    result: RacingItem[];
}

//Custom exception thrown by the API.
export class APIException {
    className: string;
}

Your Service

In your Service, you just create params with these callback types.

Then, pass them on to the HttpClientExt's get method.

import { Injectable, Inject } from '@angular/core'
import { RacingResponse, APIException } from '../models/models'
import { HttpClientExt, IObservable, IObservableError, ResponseType, ErrorType } from 'angular-extended-http-client';
.
.

@Injectable()
export class RacingService {

    //Inject HttpClientExt component.
    constructor(private client: HttpClientExt, @Inject(APP_CONFIG) private config: AppConfig) {

    }

    //Declare params of type IObservable<T> and IObservableError<TError>.
    //These are the success and failure callbacks.
    //The success callback will return the response objects returned by the underlying HttpClient call.
    //The failure callback will return the error objects returned by the underlying HttpClient call.
    getRaceInfo(success: IObservable<RacingResponse>, failure?: IObservableError<APIException>) {
        let url = this.config.apiEndpoint;

        this.client.get(url, ResponseType.IObservable, success, ErrorType.IObservableError, failure);
    }
}

Your Component

In your Component, your Service is injected and the getRaceInfo API called as shown below.

  ngOnInit() {    
    this.service.getRaceInfo(response => this.result = response.result,
                                error => this.errorMsg = error.className);

  }

Both, response and error returned in the callbacks are strongly typed. Eg. response is type RacingResponse and error is APIException.

You only deal with your Models in these strongly-typed callbacks.

Hence, The rest of your code only knows about your Models.

Also, you can still use the traditional route and return Observable<HttpResponse<T>> from Service API.

Shane
  • 81
  • 1
  • 4
0

HttpClient is a new API that came with 4.3, it has updated API's with support for progress events, json deserialization by default, Interceptors and many other great features. See more here https://angular.io/guide/http

Http is the older API and will eventually be deprecated.

Since their usage is very similar for basic tasks I would advise using HttpClient since it is the more modern and easy to use alternative.

Chirag
  • 509
  • 1
  • 6
  • 15