This blog takes the form of a tutorial to show how to use Observables in Angular 4 to get data from an API service.
Background
The Angular JS framework has gained a lot of popularity over the last couple of years. Establishing itself as one of the top choices out there for developers when they choose a framework for front-end development. There are quite a few front-end frameworks developers can choose from, such as React JS, Foundation, Bootstrap. The choice often depends on the specific requirements of the project. Frameworks can also be used in tandem with one another, such as using Angular JS and Bootstrap together. The graph below illustrates the Google search interest over the last two years for both Angular JS and React JS, where Angular is the blue line and React is the red line.
In this blog we’ll be focussing on a very specific aspect of the Angular ecosystem, known as Observables. Our main focus will be to retrieve data from an API by making use of Observables and to display the data in an HTML page. This blog post will only cover high-level detail elements of all topics discussed.
Promises vs. Observables
Promises represent a single value that returns sometime in the future, whereas Observables represent 0 or more values that either return immediately or sometime in the future.
Based on this we can derive that there are functional differences between the two paradigms. Promises work only with single values, whilst Observables do not. Promises are only asynchronous where Observables are either synchronous or asynchronous. Having said that, there are plenty of other features that Observables support that Promises do not. Observables support another function called the toPromise() function where you can cast the Observable to a Promise.
Using Observables to do an HTTP call and display data
As stated before the main focus for this blog is to demonstrate how you can make use of an Observable design pattern to retrieve data from an API. To make things simpler I’ve chosen to make use of a “fake” REST API service where the data returned from the server is in JSON format. The “fake” REST API service that I’ll be using is: https://jsonplaceholder.typicode.com/
I’ll be working with the “posts” endpoint.
The Structure of the JSON response
- userId = This is the user’s id which created the post
- id = This is the post’s id reference
- title = This is the title of the post
- body = This is the body of the post
App Module
Make sure that you have imported Angular’s HTTP module in your app.module.ts file, as that’s what we’ll be using.
An example can be found in the code block 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"; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FormsModule, HttpModule ], providers: [], bootstrap: [ AppComponent ] }) export class AppModule { }
IPosts Model for the JSON Structure
export interface IPosts { userId: number; id: number; title: string; body: string; }
Coding the service
We could make use of the component to implement our HTTP call, however, that would mean that the component’s code will get cluttered and it’ll take on more responsibility. Creating reusable services, which can be injected into your component’s constructor, is a far better approach. This makes your code more generic, reusable and easier to maintain or refactor.
import {Injectable} from "@angular/core"; import {Http, Response} from "@angular/http"; import {Observable} from "rxjs/Observable"; import "rxjs/Rx"; import {IPosts} from "./posts"; @Injectable() export class ApiService { private _postsURL = "https://jsonplaceholder.typicode.com/posts"; constructor(private http: Http) { } getPosts(): Observable<iposts[]> { return this.http .get(this._postsURL) .map((response: Response) => { return <iposts[]>response.json(); }) .catch(this.handleError); } private handleError(error: Response) { return Observable.throw(error.statusText); } }</iposts[]></iposts[]>
As can be seen in the code block above we annotate the ApiService class with the @Injectable decorator. This allows the service to be injected into a component. We need to have the @Injectable decorator because we’re making use of the Http service, provided by Angular, in the service’s constructor.
A private variable is created with the URL endpoint for the retrieval of the Posts from our API server.
The getPosts method is declared to be of type Observable, the Observable will be casted to an array type IPosts (which is an interface model I’ve made to mimic the JSON structure of the posts on the server). We map the response of the HTTP GET request to a JSON array of type IPosts and return it. If there is an error, we can catch it and handle it accordingly. Keep in mind that in a production environment your handleError method should look vastly different to the code above.
Coding our Component
import {Component, OnInit} from "@angular/core"; import {ApiService} from "./api.service"; import {IPosts} from "./posts"; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], providers: [ApiService] }) export class AppComponent implements OnInit { _postsArray: IPosts[]; constructor(private apiSerivce: ApiService) { } getPosts(): void { this.apiSerivce.getPosts() .subscribe( resultArray => this._postsArray = resultArray, error => console.log("Error :: " + error) ) } ngOnInit(): void { this.getPosts(); } }
We can inject the ApiService into our application in a few ways. One way could be to import it as a provider in your AppModule. Doing that would make it available to all components, which then can invoke it in their constructors to make use of the ApiService. Another way would be to add a providers clause to your @Component decorator and inject it on a component level. Doing this means that no other component will be able to make use of the ApiService unless you inject it into their @Component’s provider clause as well.
We declare a variable called _postsArray which is an array of type IPosts. This is the variable we’ll use to iterate over our posts data in the HTML later on.
In the constructor we instantiate our ApiService and make all of its methods available to the AppComponent class.
The getPosts method returns nothing, hence it’s of the type void. We simply have to invoke our apiService instance variable and call its getPosts method in order to continue. Because we’re making use of Observables, we need to subscribe to the apiService’s getPosts method (which is of type Observable) in order to tell the Angular eco-system that it should execute that method and in turn make the HTTP GET call. If you don’t subscribe to the Observable it won’t be executed. We then map the returned data (resultArray) to our _postsArray variable.
For simplicity, I’ve invoked the component’s getPosts method in the ngOnInit lifecycle event method. This will result in the Observable execution once our component has rendered.
Displaying our Data
There are various ways in which you can make use of data binding in the Angular framework. One way, and according to the official Angular documentation, the easiest way, is to make use of interpolation. What happens is that you bind a property name in your view template by making use of double curly braces {{ value }}.
<div class="container"> <div class="row"> <table class="table"> <thead class="thead-inverse"> <tr> <th class="text-center">User ID</th> <th class="text-center">ID</th> <th class="text-center">Title</th> <th class="text-center">Body</th> </tr> </thead> <tbody> <tr *ngFor="let post of _postsArray"> <td class="text-center" style="width: 15px;">{{post.userId}}</td> <td class="text-center" style="width: 15px;">{{post.id}}</td> <td class="text-center" style="width: 200px;">{{post.title}}</td> <td class="text-center">{{post.body}}</td> </tr> </tbody> </table> </div> </div>
I’m using Bootstrap 4 for the CSS library to make things easy. The class names of the div tags should look familiar to you if you have used the Bootstrap framework before. I’ve chosen to display the results in an HTML table. I’ve declared headers for all of the properties in the JSON structure. By making use of a simple *ngFor we can iterate through our _postsArray array list and then make use of interpolated data bindings to display the results.
Last thoughts
See how easy it was to make use of Observables to get and display data in the Angular eco-system. Observables still has a plethora of features to be explored and mastered. Keep in mind that if you want to make use of reactive programming paradigms that you need to understand the inner workings of features such as Observables in order to use them effectively in your system.
You can get more information on the Angular framework by going through the official documentation, which can be found at the following link: https://angular.io/docs
If you have any ideas or requests for a more in-depth blog about using Observables or any other Angular 2+ feature, feel free to share it with us in the comment section below.
If you liked this blog, you may also be interested in: