To do a REST call from within an Angular2 app, it is highly recommended to use the observer pattern, since this gives you the flexibility of asynchronous loads and much more.The easiest way is to use the Observable implementation from the Reactive framework. This allows you to use the observable pattern without the hassle to code such an pattern by your own. Since there are different approaches to setup, call the REST service and read data, I’m gonna show you one of the easiest approaches to reach this goal step by step.

Prerequisites

This tutorial is based on Angular2, version 4.0.0.

You can  download the sources of this tutorial from github: https://github.com/sniederm/tutorial-ng2-rest-service. But I would recommend to build it by your own using the Angular2 CLI. If not already done, you can install it globally by:

npm install -g @angular/cli

With this tool in hand, you can then create a skeleton for new Angular2 apps easily:

ng new tutorial-ng2-rest-service

You can also start a tiny server for development purposes, which allows you to visit changes immediately at http://localhost:4200:

ng serve

I also  recommend to use the Chrome browser to visit the results, since it has very good developer tools support built-in.

Step 1: Create the model

Since in Angular2 (with TypeScript) we would like to program strictly object oriented, the first thing we should do is to create a model object to be displayed. For this, we will create a class User and place it in a file called user.ts within the “to-be-created” subfolder app/models.

export class User {
   constructor(
      public id: string,
      public name: string,
      public username: string,
      public email: string
   ) {}
}

Within the User class we define several properties like id, name, username and email. These properties will be filled-up with values coming from our REST service later on.

Step 2: Create the REST service

Historically, being a programming pattern for the backend development, a service is primarily a class which provides loading and writing data from or to a sink like a database or a data service. Sometimes it is also called a “repository” or “DAO” (data access object). We gonna use this approach also on the client side in Angular2. For this, create a new class called UserService as shown below within the “to-be-created” subfolder app/services in a file namely user.service.ts.

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { User } from "app/models/user";

@Injectable()
export class UserService {
   constructor(private http: Http) {
   }

   getUsers(): Observable<User[]> {
      return this.http.get("https://jsonplaceholder.typicode.com/users")
         .map((res: Response) => res.json())
         .catch((error: any) => Observable.throw(error.json().error || 'Server error'));
   }
}

@Injectable

OK, now that we have the service, lets discuss it more in detail. As you can see, we put the decorator @Injectable on the class level. This marks it as ready for “auto-creation” and injection by the framework. Side note: A decorator looks like an annotation but it isn’t. If you are interested in the differences, read more here.

Http

Next, we use the class Http from Angular2 and put it as private into the constructor. This approach makes it available within the class as member variable http.

getUsers()

After that, we defined the method getUsers(…). This simple read-only method will return all users from a given REST service and convert the retrieved JSON format into the model of type User. Important: The method returns an Observable which holds an array of Users in turn. The caller of getUsers can then subscribe on that Observable and will be notified once the User array receives values (loading and conversion was successful). We will see that later.

this.http.get(…)

The REST call itself is done using this.http.get(…). As url we use https://jsonplaceholder.typicode.com/users which is a dummy JSON service that will return some user values as JSON.

map(…)

Defining map(…) afterwards, the JSON document will be converted into User objects. By default, the members of the model Users will be matched from the JSON elements with same name. But you can define your own mapping rules here if you want.

catch(..)

With the catch(…) definition we catch any error for now.

Step 3: Register the service

After you have created the service, you need to register it in your Angular2 app. Open the file app.module.ts, import your UserService, and add it to the providers as shown below:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { UserService } from "app/services/user.service";

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

Step 4: Use the service within a component

OK, now that the service is ready for usage within your component, open the file app.component.ts and add the following highlighted lines to it:

import { Component } from '@angular/core';
import { UserService } from "app/services/user.service";

@Component({
selector:'app-root',
templateUrl:'./app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
   title = 'app works!';
   users;

   constructor(private userService: UserService) {
      this.users = userService.getUsers();
   }
}

As you can see, we put the UserService as private into the constructor as parameter in order to be able to access it from inside the component. Angular2 injects it automatically for us.

Within the constructor body we call the getUsers(…) method on the UserService. This will return a observable, we put into the member variable users, but will not yet call the REST service. For this, we need to subscribe to the observable as shown in the next step.

Note: There are different ways to subscribe to this observable. If you want to read more about the other possibilities, read on here.

Step 5: Display the values in the template

As a last development step we need to display the values returned by the REST service on the website. For this, open the template app.component.html and add these lines below the title:

<div>
<ul>
<li *ngFor="let user of users | async">{{user.name}}</li>
</ul>
</div>

This is an ordinary ngFor iterator over all User objects of the users array, as defined under the same name within the AppComponent. But wait, it’s a bit more than that: As you already know, the users object within AppComponent is an obersvable and not just a “simple” array. Since ngFor also “knows” how to iterate over observables, the only thing we have to add here is | async. This makes sure ngFor subcribes to the observable for us and loads the values from the JSON REST call into our model User once the view got rendered. For more information about the async pipe have a look here.

Alternatives to subscribe with async

In Step 5 you can see, how to subscribe to an observer by using the pipe async in the template. For most cases this is the easiest and best way. An alternative is, to subscribe in the component’s constructor as shown below, and remove the async pipe from the template:

import { Component } from '@angular/core';
import { UserService } from "app/services/user.service";

export class AppComponent {

   title = 'app works!';
   users;

   constructor(private userService: UserService) {
      userService.getUsers().subscribe(p=>this.users = p);
   }
}

In this case the users get loaded, mapped and assigned to the member this.users once the class was instanciated. A second approach could be to implement the Angular2 interface OnInit. This interface defines the method ngOnInit() which gets automatically called by the framework when the component gets initialized.

import { Component, OnInit } from '@angular/core';
import { UserService } from "app/services/user.service";

export class AppComponent implements OnInit {

   title = 'app works!';
   users;

   constructor(private userService: UserService) {
   }

   ngOnInit() {
      this.userService.getUsers().subscribe(p=>this.users = p);
   }
}

Which one of these three approaches fits best, depends on your personal preferences as well as on your additional requirements. In my opinion, for most cases using the async pipe solution shown first is the cleanest and easiest approach.

Step 6: Show the view

To display the result in the browser, step into the folder tutorial-ng2-rest-service using your terminal and type in

ng serve

This will start the built-in webserver and after that you can visit the result in your web browser using the url http://localhost:4200. You should see a result similar to this:

Bildschirmfoto 2017-04-12 um 10.57.52

Congrats about your first Angular2 REST service!

4 comments

  1. Hallo Stephan

    Vielen Dank für die wirklich tolle und vor allem ausführliche Beschreibung der Funktion von Observables. Auch wenn ich noch immer nicht ganz dahinter sehe, konnte ich meine “Herausforderung” mit deinen Beispielen lösen.

    Grüsse aus der Schweiz
    Hampa

  2. Thanks very much for this excellent tutorial! Can anyone why when I try to change the display from a list to a table, I get an undefined on name such as with this code:

    User

    {{user.name}}

Leave a comment