Читать книгу Angular - Manfred Steyer - Страница 58
Auf das Backend zugreifen
ОглавлениеFür Ihre Hauptaufgabe muss die FlightSearchComponent via HTTP auf eine Web-API mit Flügen zugreifen. Für solche Vorhaben bietet Angular die Klasse HttpClient. Da diese Klasse wiederverwendbare Dienste anbietet, ist hierbei auch von einem Service die Rede.
Um Zugriff auf den Service zu bekommen, müssen Sie zunächst das HttpClient Module in Ihr AppModule importieren (siehe Beispiel 3-4).
Beispiel 3-4: HttpClientModule in das AppModule importieren
// src/app/app.module.ts
[...]
// Diese Zeile einfügen:
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
//Diese Zeile unter *imports* einfügen:
HttpClientModule,
BrowserModule
],
declarations: [
[...]
],
providers: [],
bootstrap: [
AppComponent
]
})
export class AppModule { }
Danach können Sie über den Konstruktor der FlightSearchComponent eine Instanz von HttpClient anfordern (siehe Beispiel 3-5).
Beispiel 3-5: HttpClient über Konstruktorargument anfordern
// src/app/flight-search/flight-search.component.ts
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { Flight } from '../flight';
@Component({
selector: 'app-flight-search',
templateUrl: './flight-search.component.html',
styleUrls: ['./flight-search.component.scss']
})
export class FlightSearchComponent implements OnInit {
from = 'Hamburg';
to = 'Graz';
flights: Array<Flight> = [];
selectedFlight: Flight | null = null;
// HttpClient anfordern.
constructor(private http: HttpClient) {
}
[...]
}
Diese Vorgehensweise nennt sich auch Dependency Injection bzw. Constructor Injection: Die benötigte Serviceinstanz wird demnach von Angular in den Konstruktor injiziert. Das bedeutet, dass Angular entscheidet, welche konkrete Ausprägung des HttpClient die Komponente erhält. Während Angular für den Produktivbetrieb den »richtigen« HttpClient erzeugt, könnte es für automatisierte Tests eine Dummy-Implementierung verwenden, die HTTP-Zugriffe lediglich simuliert.
Weitere Details zu diesem Mechanismus finden sich in Kapitel 12.
Da wir nun unsere HttpClient-Instanz haben, können wir damit innerhalb von search auf die Web-API zugreifen (siehe Beispiel 3-6).
Beispiel 3-6: Implementierung von search
// src/app/flight-search/flight-search.component.ts
// Wir benötigen diese drei Importe für den HttpClient:
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { Flight } from '../flight';
@Component({
selector: 'app-flight-search',
templateUrl: './flight-search.component.html',
styleUrls: ['./flight-search.component.scss']
})
export class FlightSearchComponent implements OnInit {
from = 'Hamburg';
to = 'Graz';
flights: Array<Flight> = [];
selectedFlight: Flight | null = null;
constructor(private http: HttpClient) {
}
ngOnInit(): void {
}
search(): void {
const url = 'http://demo.ANGULARarchitects.io/api/flight';
const headers = new HttpHeaders()
.set('Accept', 'application/json');
const params = new HttpParams()
.set('from', this.from)
.set('to', this.to);
this.http.get<Flight[]>(url, {headers, params}).subscribe({
next: (flights) => {
this.flights = flights;
},
error: (err) => {
console.error('Error', err);
}
});
}
select(f: Flight): void {
this.selectedFlight = f;
}
}
Die Methode search ruft nun via HTTP Flüge ab und hinterlegt sie in der Eigenschaft flights:
Die zu nutzenden HTTP-Kopfzeilen stellt der HttpClient mit einer Instanz von HttpHeaders dar. Das Beispiel übergibt die Kopfzeile Accept, um anzugeben, dass wir JSON als Antwortformat wünschen. Dabei handelt es sich um das einzige Datenformat, das Angular ab Werk unterstützt.
Die zu übersendenden URL-Parameter repräsentiert der HttpClient mit einer HttpParams-Auflistung.
Bitte beachten Sie, dass die beiden Aufrufe von set die aktuelle Auflistung nicht verändern, sondern eine neue Auflistung zurückliefern. Deswegen verkettet das Beispiel auch die einzelnen Aufrufe von set.
Die Methode get führt einen HTTP-Zugriff unter Verwendung der HTTP-Methode GET durch. Diese Methode kommt typischerweise zum Abrufen von Daten zum Einsatz.
Als Ergebnis des HTTP-Aufrufs erwartet der HttpClient ein JSON-Dokument, das er in ein JavaScript-Objekt umwandelt. Den Datentyp dieses Objekts nimmt get als Typparameter entgegen (Flight[]).
Das Abrufen von Daten erfolgt im Browser asynchron, also im Hintergrund. Sobald die Daten vorliegen, bringt der HttpClient eine der beiden bei subscribe registrierten Methoden zur Ausführung: next im Erfolgsfall und error in Fehlerfall. Das Objekt, das die Methode subscribe anbietet, ist übrigens ein sogenanntes Observable. Mehr zu diesem Thema findet sich in Kapitel 11.
Neben der hier verwendeten Methode get bietet der HttpClient noch weitere Methoden für andere Arten von HTTP-Zugriffen.
Tabelle 3-1: Methoden von HttpClient
Methode | Semantik |
get<T>(url, options) | Abrufen von Ressourcen. |
post<T>(url, body, options) | Hinzufügen einer Ressource oder Anstoßen einer Verarbeitung am Server. |
put<T>(url, body, options) | Hinzufügen oder Aktualisieren einer Ressource. |
patch<T>(url, body, options) | Aktualisieren einer Ressource. Es müssen nur die geänderten Eigenschaften übergeben werden. |
delete<T>(url, options) | Löschen einer Ressource. |
Der Begriff Ressource kommt aus der Welt von HTTP und bezeichnet das abgerufene oder zu sendende Objekt bzw. Dokument. Der Typparameter T steht für den Datentyp der Antwort. Im oben betrachteten Beispiel war das Flight[]. Jene Methoden, die Daten zum Server senden, weisen einen Parameter body auf. Dieser nimmt das zu sendende Objekt entgegen. Für die Übertragung per HTTP wandelt der Http Client es in ein JSON-Objekt um. Der Parameter options erhält ein Objekt, das die HTTP-Anfrage näher beschreibt. Im oben gezeigten Beispiel verweist es auf die zu sendenden Kopfzeilen sowie auf die zu verwendenden URL-Parameter.
Bitte beachten Sie auch, dass nicht jede Web-API alle hier beschriebenen Methoden unterstützt. Außerdem muss die implementierte Semantik dieser Methoden nicht jener von HTTP beschriebenen entsprechen. Beispielsweise könnten sich die Autoren einer Web-API entscheiden, aufgrund eines empfangenen post-Aufrufs serverseitige Ressourcen zu aktualisieren, obwohl hierfür put oder patch vorgesehen ist. Aufschluss darüber bietet jeweils die Dokumentation der einzubindenden Web-API.
Zur Veranschaulichung erzeugt die Methode in Beispiel 3-7 einen neuen Flug.
Beispiel 3-7: Einen neuen Flug mit post erzeugen
createDemoFlight(): void {
const url = 'http://demo.ANGULARarchitects.io/api/flight';
const headers = new HttpHeaders()
.set('Accept', 'application/json');
const newFlight: Flight = {
id: 0,
from: 'Gleisdorf',
to: 'Graz',
date: new Date().toISOString()
};
this.http.post<Flight>(url, newFlight, { headers }).subscribe({
next: (flight) => {
console.debug('Neue Id: ', flight.id);
},
error: (err) => {
console.error('Error', err);
}
});
}
Das Beispiel geht davon aus, dass der erzeugte Flug samt der serverseitig vergebenen ID wieder zurückgeliefert wird.
Falls Sie diese Methode ausprobieren möchten, können Sie sie im Konstruktor der Komponente aufrufen (this.createDemoFlight()).