Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Upgrade to Angular 5 and HttpClient

4.75/5 (4 votes)
26 Dec 2017CPOL3 min read 72.1K  
Upgrade to Angular 5 and HttpClient while Http is deprecated in NG5

Introduction

If you have applications built on Angular 2 or 4, moving to Angular 5 released on 1st November 2017 (2nd November AEST +10) is seamless. Your applications will enjoy most good things of Angular 5 right away.

HttpClient was introduced in Angular 4.3, and according to the ChangeLog of Angular at section "5.0.0 pentagonal-donut (2017-11-01)":

http: deprecate @angular/http in favor of @angular/common/http (#18906) (72c7b6e)

Surely, your existing codebase with the Http service is still working fine with next few releases of Angular, until the Angular team decides to remove @angular/http.

If you (team) have some time slots to do maintenance / refactoring works, it may be time to migrate to HttpClient@angular/common/http.

Remarks

  • If you are using Angular Material 2 Beta 12, you may have to be careful, as reported here. The good thing is, Material2 5.0.0-rc0 cesium-cephalopod (2017-11-06) had the problem fixed, and is also using HttpClient.

Upgrade

Step 0: Update NG modules in node_modules

In package.json, you should have the following or alike:

JavaScript
"dependencies": {
   "@angular/animations": "^5.0.0",
   "@angular/cdk": "^2.0.0-beta.12",
   "@angular/common": "^5.0.0",
   "@angular/compiler": "^5.0.0",
   "@angular/compiler-cli": "^5.0.0",
   "@angular/core": "^5.0.0",
   "@angular/forms": "^5.0.0",
   <s>"@angular/http": "^5.0.0",</s>
   "@angular/platform-browser": "^5.0.0",
   "@angular/platform-browser-dynamic": "^5.0.0",
   "@angular/platform-server": "^5.0.0",
   "@angular/router": "^5.0.0",

Delete the whole node_moodules folder, and run npm install.

Noted that the package for the Http service may be removed, though leaving it there does not harm. Also, if you have other 3rd party NG2 components that depend on the Http service, you may still need the deprecated Http service coexisting with the HttpClient service before the vendors could provide upgrades.

Remarks

You may have your own favorite update methods, then just go ahead.

Step 1: Refine systemjs.config.js

JavaScript
map: {
    app: 'app',
    // angular bundles
    '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
    '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
    '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
    '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
    '@angular/platform-browser-dynamic':
    'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
    '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
    '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
    '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
    '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js',
    '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js',
    '@angular/platform-browser/animations':
    'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js',

    '@angular/cdk': 'npm:@angular/cdk/bundles/cdk.umd.js',
    '@angular/cdk/a11y': 'npm:@angular/cdk/bundles/cdk-a11y.umd.js',
    '@angular/cdk/bidi': 'npm:@angular/cdk/bundles/cdk-bidi.umd.js',
    '@angular/cdk/coercion': 'npm:@angular/cdk/bundles/cdk-coercion.umd.js',
    '@angular/cdk/collections': 'npm:@angular/cdk/bundles/cdk-collections.umd.js',
    '@angular/cdk/keycodes': 'npm:@angular/cdk/bundles/cdk-keycodes.umd.js',
    '@angular/cdk/observers': 'npm:@angular/cdk/bundles/cdk-observers.umd.js',
    '@angular/cdk/overlay': 'npm:@angular/cdk/bundles/cdk-overlay.umd.js',
    '@angular/cdk/platform': 'npm:@angular/cdk/bundles/cdk-platform.umd.js',
    '@angular/cdk/portal': 'npm:@angular/cdk/bundles/cdk-portal.umd.js',
    '@angular/cdk/rxjs': 'npm:@angular/cdk/bundles/cdk-rxjs.umd.js',
    '@angular/cdk/scrolling': 'npm:@angular/cdk/bundles/cdk-scrolling.umd.js',
    '@angular/cdk/stepper': 'npm:@angular/cdk/bundles/cdk-stepper.umd.js',
    '@angular/cdk/table': 'npm:@angular/cdk/bundles/cdk-table.umd.js',

    'tslib': 'npm:tslib/tslib.js',
    // other libraries
    'rxjs': 'npm:rxjs',
    //temp fix according to https://github.com/ReactiveX/rxjs/issues/2971
    'rxjs/operators': 'npm:rxjs/operators/index.js'

Particularly, add '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js' and 'tslib': 'npm:tslib/tslib.js', and optionally remove the mapping for '@angular/http'.

Step 2: Replace All Http Declarations with HttpClient

In each xxx.module.ts,

Replacement 1

Replace:

JavaScript
import { HttpModule, Http, ... } from '@angular/http'

with:

JavaScript
import { HttpClientModule, HttpClient, ... } from '@angular/common/http'

And in the imports section of @NgModule, replace HttpModule with HttpClientModule.

Hints

Make sure you search from @angular/http in every TS/JS files. Even if your app code is not using the import, the import may still try to download the js lib, and give you some strange 404 error in browser's console.

Replacement 2

In Angular 4.3 with the Http service, you may have to provide the following in the providers section of app.module.ts:

JavaScript
{
    provide: Http,
    useFactory: httpFactory,
    deps: [XHRBackend, RequestOptions]
},

In Angular 5 with the HttpClient service, this is not needed. So, simply remove it without providing HttpClient explicitly for DI.

Replacement 3

Comparing with Http, HttpClient provides high level abstractions for application programming.

With Http, your app code is typically like:

JavaScript
http.get(this.baseUri + 'api/Entities'+id)
.map(response=> response.json())
.subscribe(
    data=>{
       ....
    },
    error=>{
    ....
    });

The data type of "data" is weak.

With HttpClient, your app code will be like:

JavaScript
httpClient.get<Entity>(this.baseUri + 'api/Entities'+id)
.subscribe(
    data=>{
       ....
    },
    error=>{
       ....
    });

The data type of "data" is strong with Observable<Entity>.

Depending on how you had deserialized the JSON data, you may have a lot of replacements to do.

Points of Interest

If you have been using WebApiClientGen for your ASP.NET WebApi + Angular2 solution, you don't need to do the step of replacement 3, since WebApiClientGen had already supported this kind of app code since Angular 2 as HttpClient supports since Angular 4.3.

With the Http service, the generated client API is like this:

JavaScript
@Injectable()
export class Entities {
    constructor(@Inject('baseUri') private baseUri: string = location.protocol + '//' +
    location.hostname + (location.port ? ':' + location.port : '') + '/', private http: Http){
    }

    /**
     * Get a person
     * so to know the person
     * GET api/Entities/{id}
     * @param {number} id unique id of that guy
     * @return {DemoWebApi_DemoData_Client.Person} person in db
     */
    getPerson(id: number): Observable<DemoWebApi_DemoData_Client.Person>{
        return this.http.get(this.baseUri + 'api/Entities/'+id).map(response=> response.json());
    }

The app code is like this:

JavaScript
entitiesService.getPerson(1001)
.subscribe(
data=>
{ ....
},
error=>{ .
...
});

The data type of "data" had already been strong with Observable<DemoWebApi_DemoData_Client.Person>.

With the HttpClient service, the client API generated by WebApiClientGen v2.3 is like this:

JavaScript
@Injectable()
export class Entities {
    constructor(@Inject('baseUri') private baseUri: string = location.protocol + '//' +
    location.hostname + (location.port ? ':' + location.port : '') + '/', private http: HttpClient){
    }

    /**
     * Get a person
     * so to know the person
     * GET api/Entities/{id}
     * @param {number} id unique id of that guy
     * @return {DemoWebApi_DemoData_Client.Person} person in db
     */
    getPerson(id: number): Observable<DemoWebApi_DemoData_Client.Person>{
        return this.http.get<DemoWebApi_DemoData_Client.Person>(this.baseUri + 'api/Entities/'+id);
    }

So your app code could remain the same, because the interface getPerson(id: number): Observable<DemoWebApi_DemoData_Client.Person> remains the same.

For more details of using WebApiClientGen for Angular2, please check:

If you have been doing Web programming using jQuery and WebApiClientGen, you may also welcome the change to HttpClient, since in the generated client API codes for jQuery, the helper class is also named as "HttpClient". And in programming .NET client, the common helper class in the last few years is System.Net.Http.HttpClient. So you have 3 frameworks of Web client programming share the same name for HTTP client helper class.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)