Qui la parte precedente dell’articolo: Creare una web application con Spring Boot, MongoDB, Angular 4 e TypeScript e deployarla in cloud come Microsoft Azure Webapp – Parte 5

Invocare le API Rest di Spring Boot da Angular

Torniamo quindi al progetto Angular4, dove dobbiamo implementare il Service che effettuerà le chiamate alle API REST esposte da Spring Boot.

Per prima cosa andiamo nella classe “app.component.ts” e commentiamo tutta la parte di creazione statica degli utenti che avevamo utilizzato prima come test. Lasciamo solo la definizione dell’array “users” che ora verrà però popolato con il risultato della chiamata che faremo al servizio Rest del back-end Spring Boot.



Andiamo ora a modificare il file TypeScript “app.module.ts”, in cui aggiungiamo l’importazione del modulo “Http” che ci permetterà di effettuare le chiamate agli endpoint delle nostre API. Per farlo modifichiamo il contenuto del file come segue:

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { UserDetailsComponent } from './user-details/user-details.component'; import { HttpModule } from '@angular/http'; @NgModule({ declarations: [ AppComponent, UserDetailsComponent ], imports: [ BrowserModule, HttpModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

Le modifiche effettuate consistono in:

1) Importazione del modulo

import { HttpModule } from '@angular/http';

2) Aggiunta del modulo nell’array degli “imports”

imports: [ BrowserModule, HttpModule ],

Creazione di un Service Angular

Definiamo un Service che chiamiamo UserAPIService:

Creiamo all’interno di “app” una nuova sottocartella che chiamiamo “services”. Qui creeremo il nostro Service. Per farlo clicchiamo con il tasto destro sul folder “services”, selezionando “New” dal menù contestuale e poi “Service”, come illustrato nella figura seguente:



Nel wizard che si apre definiamo il nome del nostro Service, utilizzando la stessa convenzione già utilizzata in precedenza per la nomenclatura dei Component, cioè inserendo un ‘–‘ nel nome dell’elemento dove vogliamo che nella classe sia trasformato in camel case



Cliccando su “Finish” inizia la creazione del Service da parte della Angular CLI che eseguirà l’opportuno comando, in questo caso: ng g service

Una volta terminata l’esecuzione del comando di creazione del service, troviamo nel nostro folder “services” due nuovi files: user-api.service.ts e user-api.service.spec.ts

user-api.service.ts è la classe che rappresenta il nostro Service che inizialmente presenta il seguente contenuto:

import { Injectable } from '@angular/core'; @Injectable() export class UserApiService { constructor() { } }



Procediamo con l’implementazione del Service.

Iniziamo definendo una stringa con l’url del servizio da chiamare. Ricordiamo che il nostro back-end è in esecuzione in locale sulla porta 8080 e che l’endpoint che avevamo definito per il controller che restituisce tutti gli utenti è “/users”. La stringa sarà quindi:

private userApiUrl = 'http://localhost:8080/users';

Definiamo un metodo getUsers che effettua una chiamata, in modo asincrono, al servizio che restituisce la lista degli utenti. La modalità asincrona prevede che il client, una volta effettuata la richiesta, non stia in attesa del risultato (modalità sincrona) ma continui la sua esecuzione e venga in qualche modo avvisato quando il risultato della chiamata è disponibile perché il server ha risposto.

Per fare questo, utilizziamo il meccanismo dei Promise. Un promise è un oggetto che viene ritornato dalla chiamata asincrona e che mette a disposizione delle callbacks che verranno invocate quando il server avrà risposto con i risultati o nel caso si sia ottenuto un errore.

Il metodo getUsers avrà quindi la seguente signature:

public getUsers(): Promise

L’implementazione di tale metodo consiste nell’effettuare la chiamata all’API esposta. Per farlo dobbiamo utilizzare il modulo http che importiamo e iniettiamo nel servizio tramite il suo costruttore. Il codice del Service a questo punto risulta essere:

import { User } from '../models/user'; import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; @Injectable() export class UserApiService { private userApiUrl = 'http://localhost:8080/users'; constructor(private http: Http) { } public getUsers(): Promise { } }

Nell’implementazione del metodo utilizziamo il modulo http iniettato per effettuare la chiamata GET al server, specificando l’endpoint definito nella stringa precedente. Tutte le chiamate get ritornano un Observable, ma non vogliamo ritornare un Promise, per cui concateniamo la chiamata toPromise().

L’operatore toPromise() non è però fornito di base dagli Observable di Angular per cui, per il nostro scopo, dobbiamo importarlo da una libreria esterna, RxJS:

import 'rxjs/add/operator/toPromise';

A questo punto la domanda può sorgere spontanea: perché convertire l’Observable in Promise e non ritornare direttamente l’Observable?

Secondo la documentazione ufficiale di Angular la conversione è una buona scelta quando, come nel caso del nostro caricamento della lista di utenti, si effettua una singola chiamata per recuperare un dato ben specifico e una volta che si ottiene il risultato lo si processa.

Con i Promise è più difficile gestire uno scenario request-cancel-new-request, in cui è possibile che venga inviata una richiesta, poi cancellata e poi ne sia inviata un’altra prima ancora che il server abbia risposto per la prima. In questo caso è più facile utilizzare gli Observables.

Per il nostro caricamento one-shot degli utenti all’avvio, quindi, continuiamo a utilizzare una Promise.

Dopo aver fatto la conversione dobbiamo concatenare la callback then() all’interno della quale dobbiamo estrarre i dati dalla risposta tramite il metodo json() e ritornarli come tipo definito dalla Promise, in questo caso array di User.

L’implementazione del metodo getUsers() sarà quindi:

public getUsers(): Promise { return this.http.get(this.userApiUrl) .toPromise() .then(response => response.json() as User[]); }

Il codice completo del servizio risulta quindi essere il seguente:

import { User } from '../models/user'; import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/toPromise'; @Injectable() export class UserApiService { private userApiUrl = 'http://localhost:8080/users'; constructor(private http: Http) { } public getUsers(): Promise { return this.http.get(this.userApiUrl) .toPromise() .then(response => response.json() as User[]); } }



Vai alla parte successiva dell’articolo: Creare una web application con Spring Boot, MongoDB, Angular 4 e TypeScript e deployarla in cloud come Microsoft Azure Webapp – Parte 7