How to work with an API
January 30, 2024About 6 min
How to work with an API
- In the end we want to
persist
our data to adatabase
- Because an
Angular
app lives entirely in thebrowser
, we will need to work with anAPI
to ensure persistence - When the
API
is running we can use Angular'sHttpClient
to communicate with theAPI
Create a simple API using JSON server
- The focus of this course is not about developing
APIs
- We do want to learn how to communicate with them and how to handle the responses!
- JSON server will get us a full fake
REST API
with zero coding!
JSON server
- Create a folder
json-server-local
in theroot
folder of your project - Install
JSON server
in the project
npm install json-server@0.17.4
json-server@0.17.4
- The version is very important here! A newer version still contains some bugs when adding an object!
- Create a
db.json
file with some data in thejson-server-local
folder
{
"articles": [
{
"id": 1,
"title": "Title article",
"subtitle": "Subtitle article",
"imageUrl": "https://images.pexels.com/photos/1202723/pexels-photo-1202723.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=100&w=134",
"imageCaption": "caption image",
"content": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur voluptas sequi voluptatum pariatur! Quae cumque quidem dolor maxime enim debitis omnis nemo facilis sequi autem? Quae tenetur, repellat vero deleniti vitae dolores? Cum tempore, mollitia provident placeat fugit earum, sint, quae iusto optio ea officiis consectetur sit necessitatibus itaque explicabo?",
"author": "Michaƫl Cloots",
"publishDate": "28/11/2020"
},
{
"id": 2,
"title": "Title article 2",
"subtitle": "Subtitle article 2",
"imageUrl": "https://images.pexels.com/photos/3422964/pexels-photo-3422964.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=100&w=134",
"imageCaption": "caption image",
"content": "2 Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur voluptas sequi voluptatum pariatur! Quae cumque quidem dolor maxime enim debitis omnis nemo facilis sequi autem? Quae tenetur, repellat vero deleniti vitae dolores? Cum tempore, mollitia provident placeat fugit earum, sint, quae iusto optio ea officiis consectetur sit necessitatibus itaque explicabo?",
"author": "Florian Smeyers",
"publishDate": "30/11/2020"
}
]
}
- Execute the following command in the
json-server-local
folder to start yourAPI
json-server --watch db.json
- Going to http://localhost:3000/articles should give the following result:
- We get these articles by performing a
HTTP
GET
request - All the other HTTP requests (
PUT
,PATCH
,DELETE
,POST
) are available as well
Tips
- You can modify the
npm start
script so you start thejson-server
and theapplication
simultaneously:
"scripts": {
"ng": "ng",
"start": "start npm run api && start ng serve -o --port 5878",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"api": "json-server --watch json-server-local\\db.json"
},
Using Angular's HttpClient to call API
- Time to refactor the
ArticleService
because we now want to get the articles from theAPI
- In Angular we can use the
HttpClient
service
from within theHttpClientModule
to easily perform ourHTTP requests
- Before we can use the
HttpClient
service
we have to provide theHttpClient
throughout the entire application. This can be done in theapp.config.ts
. - This way dependency injection will be applied when we're asking for the
HttpClient
in every component!
//app.config.ts
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes),
provideHttpClient()]
};
- Next we have to
inject
theHttpClient
service
in theconstructor
of theArticleService
- We also refactor our 2 methods to work with the
HttpClient
//article.service.ts
import { Injectable } from '@angular/core';
import { Article } from './article';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ArticleService {
constructor(private httpClient: HttpClient) {
}
getArticles(): Observable<Article[]> {
return this.httpClient.get<Article[]>("http://localhost:3000/articles");
}
getArticleById(id: number): Observable<Article> {
return this.httpClient.get<Article>("http://localhost:3000/articles/" + id);
}
}
code | description |
---|---|
constructor(private httpClient: HttpClient) { ... } | injects the HttpClient service into a private httpClient property |
this.httpClient.get<Article[]>("http://localhost:3000/articles"); | perform a HTTP GET request on the provided url |
this.httpClient.get<Article>("http://localhost:3000/articles/" + id); | perform a HTTP GET request on the provided url |
import { Observable } from 'rxjs'; | each HTTP request you perform with the HttpClient returns an Observable . This is a class defined in the rxjs library . More info on observables later! |
this.httpClient.get()
- Let's break down the
get
method from theHttpClient
getArticles(): Observable<Article[]>
: our method returns anObservable
of anArticle Array
get<Article[]>
: we defineArticle[]
betweenget<...>
as the result type (generics
). This result type is at the end wrapped up in anObservable
- You don't have to define a return type. In that case the result will always be of the type
Observable<Object>
. Because we like to work with types (and it saves us some headaches later on) we prefer defining them!
Observables
- There is a lot to tell about
Observables
- In this course we'll only discuss the topics about
Observables
that come in handy within an Angular application - What you should know right now
- RxJS is a framework for
reactive programming
which makes it very easy to writeasynchronous
code - An
Observable
is basically a function that can return astream of values
to anobserver
over time- A
stream
is a sequence of data values over time - In our
getArticles()
method
astream
is the articles we get back from theAPI
- A
- Because we are working
asynchronously
we don't know when in time we will get the result- Therefore we always need one or more
subscribers
in order to make theObservable
do its work! - A
subscriber
subscribes
to theObservable
which allows him to execute acode block
when the result is ready!
- Therefore we always need one or more
- RxJS is a framework for
Services
- The place in Angular where you call an
API
is aservice
Components
should be as simple and stupid as possible, so we improve:- Readability
- Maintainability
- Testability
- Never write complex business logic or data access logic in your
components
!
- In the
ArticleDetailComponent
we need to modify some code to work correctly with theObservable
we get back from ourservice
//article-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ArticleComponent } from '../article/article.component';
import { Article } from '../article';
import { ArticleService } from '../article.service';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-article-detail',
standalone: true,
imports: [ArticleComponent],
templateUrl: './article-detail.component.html',
styleUrl: './article-detail.component.css'
})
export class ArticleDetailComponent implements OnInit {
article!: Article;
constructor(private articleService: ArticleService, private route: ActivatedRoute) { }
ngOnInit(): void {
const articleId = this.route.snapshot.paramMap.get('id');
if (articleId != null) {
this.articleService.getArticleById(+articleId).subscribe(result =>
this.article = result);
}
}
}
- The
.subscribe(result => this.article = result)
subscribes to theObservable
. When theHTTP GET request
is completed theresult
is assigned to thearticle
property - The
template
is still working without code changes. This proves that we are doing a great job on separation of concerns!
Subscribe!
- Without a
.subscribe()
theAPI
call will never be executed!
- We also have to update the
HomeComponent
to work correctly with theObservable
- Here we will use a different approach for subscription using the
async pipe
//home.component.ts
import { Component } from '@angular/core';
import { Article } from '../article';
import { ArticleService } from '../article.service';
import { ArticleComponent } from '../article/article.component';
import { Observable } from 'rxjs';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-home',
standalone: true,
imports: [ArticleComponent, CommonModule],
templateUrl: './home.component.html',
styleUrl: './home.component.css'
})
export class HomeComponent {
articles$: Observable<Article[]> = new Observable<Article[]>();
constructor(private articleService: ArticleService) { }
ngOnInit(): void {
this.articles$ = this.articleService.getArticles();
}
}
- We declare a new
property
articles$
for theObservable
we get back from ourArticleService
- Because of the strict
TypeScript
rules we have to initialise ourObservable
using the= new Observable<Article[]>()
- Instead of subscribing to the
Observable
we assign it to ourarticles$
property
async
- The
async
pipe is part of theCommonModule
. We have to import it in our component to be able to work with theasync
pipe in the template!
articles$
- A property/variable of the type
Observable
is always suffixed with the$
sign. This is not required, but most developers use this naming convention because it's easy to determine which property is anObservable
- The
subscription
is happening in thetemplate
using theasync pipe
, thus we have to modify thetemplate
<h1 class="text-4xl">Welcome home</h1>
<div class="grid grid-cols-1 md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-3 mx-auto py-6">
@for (article of articles$ | async; track $index) {
<app-article [article]="article"></app-article>
}
</div>
- When the
@for
is executed, theasync pipe
subscribes
to thearticles$
Observable
and returns the latest value it has emitted
Polling
- Recall this phrase:
Observables
can return astream of values
to anobserver
over time - At the moment we only call our
API
once (onsubscription
) so we only getone stream
back- When new articles are added to the database, we don't get them automatically
- To prove the power of
Observables
we will implement apolling mechanism
with only modifying 1 line of code - We want to keep calling the
API
every 3 seconds. Therefore we use 2 extraRxJS
operators
:timer
andswitchMap
and we use thepipe
method tochain
them together
//article.service.ts
import { Observable, switchMap, timer } from 'rxjs';
...
getArticles(): Observable<Article[]> {
return timer(1, 3000).pipe(switchMap(() => this.httpClient.get<Article[]>("http://localhost:3000/articles")));
}
code | description |
---|---|
timer(1, 3000) | Creates an Observable that starts emitting after a given duration (1 millisecond) and keeps emitting after each period of time (3 seconds) |
.pipe( ... ) | chain together all the functions that take, and return an Observable |
switchMap(() => | switch to a new Observable , in this case our call to the API through the HttpClient |
- Check the
Network
tab in the Developer Tools and you will see that we make anAPI
call every 3 seconds

db.json
- You can also verify the
polling
by adding, changing or removing an article in thedb.json
file - Within 3 seconds the changes are reflected in your application!
Polling & Observables
- This is only one possible solution for working with realtime data
- Calling your
API
every n seconds could be not so ideal because of performance issues and data traffic - Having a lot of
subscriptions
on a lot ofObservables
can result in memory leaks. Later on we will discuss how we can safely avoid these issues, but for now:async pipe
: automaticallyunsubscribes
if thecomponent
is destroyed.subscribe()
: you have tounsubscribe
manually, preferrably in thengOnDestroy
method of thecomponent