How to call an rest api while bootstrapping angular 2 app

Angular

Angular Problem Overview


We would like to call a rest api when angular 2 app being bootstrapped, i mean first thing it should do about the application is call this api and get some data which is required for application.

Is there anyway to achieve this? I saw following article but it was meant for beta version of Angular 2

Sample Code based on Angular 2 beta or rc

[Reading data before app start up][2]

[2]: https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9 "Reading Data before app start up"

Angular Solutions


Solution 1 - Angular

You can use APP_INITIALIZER to call a service method at bootstrap. You will require to define a provider for it in your AppModule.

Here is an example of how to do this.

StartupService (startup.service.ts)

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

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';

@Injectable()
export class StartupService {

    private _startupData: any;

    constructor(private http: Http) { }

    // This is the method you want to call at bootstrap
    // Important: It should return a Promise
    load(): Promise<any> {

        this._startupData = null;

        return this.http
            .get('REST_API_URL')
            .map((res: Response) => res.json())
            .toPromise()
            .then((data: any) => this._startupData = data)
            .catch((err: any) => Promise.resolve());
    }

    get startupData(): any {
        return this._startupData;
    }
}

AppModule (app.module.ts)

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '@angular/core';

import { StartupService } from './startup.service';

// ...
// Other imports that you may require
// ...


export function startupServiceFactory(startupService: StartupService): Function {
    return () => startupService.load();
}

@NgModule({
    declarations: [
        AppComponent,
        // ...
        // Other components & directives
    ],
    imports: [
        BrowserModule,
        // ..
        // Other modules
    ],
    providers: [
        StartupService,
        {
            // Provider for APP_INITIALIZER
            provide: APP_INITIALIZER,
            useFactory: startupServiceFactory,
            deps: [StartupService],
            multi: true
        }
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

EDIT (How to handle startup service failure):

AppComponent (app.component.ts)

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { StartupService } from './startup.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

    constructor(private router: Router, private startup: StartupService ) { }

    ngOnInit() {

        // If there is no startup data received (maybe an error!)
        // navigate to error route
        if (!this.startup.startupData) {
            this.router.navigate(['error'], { replaceUrl: true });
        }
    }

}

Solution 2 - Angular

One thing I came across using the answer provided by Santanu is that it won't work unless StartupService is defined in the providers before the APP_INITIALIZER. I'm using Angular 4.x, so the providers part looks like this in my case:

providers: [
  UserService,
  {
    provide: APP_INITIALIZER,
    useFactory: userServiceFactory,
    deps: [UserService],
    multi: true
  }
]

Solution 3 - Angular

> @efirvida & @Santanu Biswas > > I tried your answer and it works (content in APP_INITIALIZER happens > before app.component bootstrapping). > > Unfortunately, the injections in all components happen before it, so > that components refer to variables not ready yet. > > I opened a question here. > > It is basically the same question that @magos asked. > > Any help well accepted ^^

The only solution I can think of is to make API calls in app.component to get config data, but is not properly what is needed for both OP and me. Will be my solution if I can't solve the syncronism issue

Solution 4 - Angular

Here is an article which explains APP_INITIALIZER in much more detail and it also shows how angular uses it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser509755View Question on Stackoverflow
Solution 1 - AngularSantanu BiswasView Answer on Stackoverflow
Solution 2 - AngularDusan MancicView Answer on Stackoverflow
Solution 3 - AngularEadenView Answer on Stackoverflow
Solution 4 - AngularNR GaneshView Answer on Stackoverflow