Feeding data from a REST endpoint to Angular components

William Ghelfi
Angular for dads
Published in
5 min readApr 11, 2019

Getting, and using, data from a REST endpoint is actually much simpler than one would assume. You just need to start getting comfortable with RxJS data streams.

Photo by Kevin Ngo on Unsplash

A word of advice

This is the first inherently difficult topic so far in “Angular for dads”. Normally you would stop right now and go read an introduction to RxJS, Observables, and whatnot.

But you don’t have time for that.

So instead I’ll do my best to keep it light and to the point, and if it really doesn’t work out for you in the end, let me know in the comments and I’ll find some good additional resources to point you at.

From static data to an observable stream

Right now we are getting data from a service and feeding it to a component.

But what happens if the data changes over time? To get it again we could rerun the application by refreshing the page. Suboptimal.

Let’s transform the static data into an observable that changes over time:

  • Install Chance.js, a faker: npm i -S chance && npm i -D @types/chance
  • Open src/persons/persons.service.ts and update it to emit a stream of 3 different random person objects over time:
import { Injectable } from '@angular/core';// rxjs
import { Observable, interval } from 'rxjs';
import { map } from 'rxjs/operators';
// Third Parties
import { Chance } from 'chance';
// App Models
import { Person } from './person.model';
@Injectable()
export class PersonsService {
private chance = new Chance();
// In the future, this will fetch data from a REST endpoint
getPersons(): Observable<Person[]> {

// Emit a value every 2 seconds
return interval(2000).pipe(
map(() => {
const persons: Person[] = [
new Person({ name: this.chance.name(), age: this.chance.age() }),
new Person({ name: this.chance.name(), age: this.chance.age() }),
new Person({ name: this.chance.name(), age: this.chance.age() }),
];
return persons;
})
);
}
}
  • Open src/app/app.component.ts and update it to use the new data stream instead of static values:
import { Component } from '@angular/core';// rxjs
import { Observable } from 'rxjs';
// App Models
import { Person } from './persons/person.model';
// App Services
import { PersonsService } from './persons/persons.service';
@Component({
selector: 'ng4d-root',
template: `
<ng4d-greeting-card
*ngFor="let person of (persons$ | async)"
[person]="person"
></ng4d-greeting-card>
`,
})
export class AppComponent {
// Always append a `$` - for stream - to an Observable property, for clarity
persons$: Observable<Person[]>;
constructor(private personsService: PersonsService) {
this.persons$ = this.personsService.getPersons();
}
}

And lo and behold: a self updating data stream!

Blame Chance for the lady names XD

Getting data from a REST endpoint

Ok, bear with me a little more: we are going to use Angular’s own HttpClient service to get data from a REST endpoint instead of using Chance to invent it at runtime.

Setting up a quick and dirty API server

Usually I’d fire up a backend with Sails.js, but we have a very simple use case to cover and JSON Server will do just fine.

  • Install JSON Server globally: npm install -g json-server
  • Create a rest-simulator directory under the root of your project
  • Create rest-simulator/index.js:
const Chance = require('chance');
const chance = new Chance();
module.exports = () => {
const data = { persons: [] };
// Create 3 persons
for (let i = 0; i < 3; i++) {
data.persons.push({ name: chance.name(), age: chance.age() });
}
return data;
};
  • Open a new terminal, move into rest-simulator, and launch the server: json-server index.js
  • Point your browser (or REST client like Postman or curl) to http://localhost:3000/persons and you should see something like this JSON:
[
{
"name": "Isaac Norton",
"age": 29
},
{
"name": "Ernest Simon",
"age": 27
},
{
"name": "Eula Clarke",
"age": 23
}
]

If you perform the same request again, you’ll get the exact same results until you stop and re-launch json-server index.js.
This is how json-server works, and it will actually come in handy once we get to user input and forms in Angular in one of the coming stories.

Using HttpClient to get the data

Now for the fun part.

  • Import HttpClientModule into app.module.ts so that you can then use HttpClient in every part of the application:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
// App Components
import { AppComponent } from './app.component';
import { GreetingCardComponent } from './greeting-card/greeting-card.component';
// App Modules
import { PersonsModule } from './persons/persons.module';
@NgModule({
declarations: [AppComponent, GreetingCardComponent],
imports: [BrowserModule, PersonsModule, HttpClientModule],
bootstrap: [AppComponent],
})
export class AppModule {}
  • Update src/persons/persons.service.ts to start fetching data from the JSON Server backend:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// rxjs
import { Observable } from 'rxjs';
// App Models
import { Person } from './person.model';
@Injectable()
export class PersonsService {
constructor(private httpClient: HttpClient) {}
getPersons(): Observable<Person[]> {
return this.httpClient.get<Person[]>('http://localhost:3000/persons');
}
}

Much simpler! Notice the service injection of HttpClient in the constructor, and the .get<Person[]>() bit which is how you tell Angular’s httpClient to which type you expect it to map the JSON response to.

And you should be able to see the request in the dev tools.

Yay data from a backend!

A quick refactor

Let’s go for the extra mile and make some preparations for when we will build a production bundle of the application.

  • Create a new directory: src/config
  • Create src/config/api.config.ts:
export const apiBaseUrl = 'http://localhost:3000';// Persons
export const apiEndpointPersons = [apiBaseUrl, 'persons'].join('/');
  • Update src/persons/persons.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// rxjs
import { Observable } from 'rxjs';
// App Configurations
import { apiEndpointPersons } from '../config/api.config';
// App Models
import { Person } from './person.model';
@Injectable()
export class PersonsService {
constructor(private httpClient: HttpClient) {}

getPersons(): Observable<Person[]> {
return this.httpClient.get<Person[]>(apiEndpointPersons);
}
}

Wrapping up

All done! This time you learned how to:

  • Use the async pipe and Observables to display an async stream of data instead of simple static values
  • Quickly fire up a REST backend simulator
  • Use Angular’s built-in HttpClient to fetch data from a REST backend

If there’s something about this topic that I can help you understand better, let me know in the comments!

--

--