Angular-Backend-Kommunikation

Aus Zweites Gehirn, dem persönlichen Wiki
Angular-Backend-Kommunikation
TypKonzept
QuellenQuelle - Angular Mastery Workshop
Quelle - Recherche - Angular heute 2026
Erstellt2026-09-26
Aktualisiert2026-09-26
Tagsangular, webentwicklung, http, backend

Wie eine Angular-App Daten vom Server holt und dorthin schickt: mit dem HttpClient, der Observables liefert, gekapselt in eigenen Backend-Services, mit Fehlerbehandlung an der Grenze und HTTP-Interceptors für alles, was jede Anfrage betrifft.

Code-Beispiele aus Quelle - Angular Mastery Workshop (Folie 286–295), von den Folienbildern abgeschrieben (Stand Angular 12).

Grundlagen

Die meisten Frontends lesen und ändern Zustand, der in einer Datenbank hinter einem oder mehreren Backend-Services liegt (Folie 286). Anfragen macht der HttpClient. Dafür muss das HttpClientModule einmal importiert werden, im AppModule oder CoreModule (Folie 287):

import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
    // ...
    imports: [
        HttpClientModule
    ]
})
export class CoreModule {}

Backend-Service

Für jede Ressource gibt es einen eigenen „Backend“- oder „Integration“-Service mit den CRUD-Methoden. Der HttpClient gibt ein Observable zurück, das die Antwort (oder einen Fehler) liefert und dann endet (Folie 288):

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { Customer } from './customer'

const RESOURCE = '/customer';

@Injectable()
export class CustomerBackendService {

    constructor(private httpClient: HttpClient) {}

    getAll(): Observable<Customer[]> {
        return this.httpClient.get<Customer[]>(RESOURCE);
    }

    getOne(id: number): Observable<Customer> {
        return this.httpClient.get<Customer>(`${RESOURCE}/${id}`);
    }

    update(customer: Partial<Customer>): Observable<Customer> {
        return this.httpClient.put<Customer>(`${RESOURCE}/${customer.id}`, customer);
    }

    // ...
}

Fehlerbehandlung

Fehler fängt man mit dem RxJS-Operator catchError ab und gibt einen gültigen Ersatzwert zurück. Tipp: Fehler möglichst früh an der Grenze der Anwendung behandeln, damit die innere Logik frei von Fehlerbehandlung bleibt (Folie 289):

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';

import { Customer } from './customer'

const RESOURCE = '/customer';

@Injectable()
export class CustomerBackendService {

    constructor(private httpClient: HttpClient) {}

    getAll(): Observable<Customer[]> {
        return this.httpClient.get<Customer[]>(RESOURCE)
            .pipe(
                catchError(error => {
                    // handle error somehow (eg log it, show notification, ...)

                    return of([]);
                })
            );
    }

    // ...
}

Testen

HttpClientTestingModule ersetzt das echte HTTP. Der Test prüft, ob die richtige URL mit dem richtigen Verb aufgerufen wurde, und liefert die Antwort mit flush(). verify() stellt sicher, dass keine Anfrage offen bleibt (Folie 290):

describe('CustomersBackendService', () => {

  let service: CustomersBackendService;
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [CustomersBackendService]
    });

    service = TestBed.get(CustomersBackendService);
    httpTestingController = TestBed.get(HttpTestingController);
  });

  afterEach(() => httpTestingController.verify());

  it('should load customer', () => {
    const MOCK_CUSTOMER = { id: 0, name: 'John', surname: 'Snow' };

    service.get(0).subscribe(customer => {
      expect(customer).toEqual(MOCK_CUSTOMER);
    });

    const req = httpTestingController.expectOne(`${RESOURCE_URL}/0`);
    expect(req.request.method).toBe('GET');
    req.flush(MOCK_CUSTOMER);
  });
});

(TestBed.get() heisst seit Angular 9 TestBed.inject(), Einordnung Claude. Der Service heisst hier CustomersBackendService mit Methode get, auf Folie 288 CustomerBackendService mit getOne.)

HTTP-Interceptors

Ein Interceptor verarbeitet jede Anfrage, bevor sie rausgeht, und jede Antwort, bevor sie ankommt, ähnlich einer Middleware. Er ist ein normaler Service, der das Interface HttpInterceptor umsetzt (Folie 291–292):

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()                                   // bewusst NICHT providedIn: 'root'
export class HttpErrorInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    return next.handle(req).pipe(               // Strom von Ereignissen

      tap({                                     // Nebeneffekt: Antworten und Fehler beobachten
        next: (event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {
            if (event.status > 201) {
              console.error('Backend request failed');
            }
          }
        },
        error: error => {
          console.error('Backend request failed');
        },
      })

    );
  }
}

Angemeldet werden alle Interceptors über das Token HTTP_INTERCEPTORS. Es ist ein Multi-Provider: Mehrere Einträge unter einem Token, beim Injizieren erhält man ein Array (Folie 293):

import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';

import { HttpErrorInterceptor } from './interceptors/http-error-interceptor.service';
import { HttpAuthHeaderInterceptor } from './interceptors/http-auth-header-interceptor.service';

@NgModule({
  // ...
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpErrorInterceptor,
      multi: true
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpAuthHeaderInterceptor,
      multi: true
    }
  ]
})
export class CoreModule {}

Einsatz (Folie 294): HTTP-Header an jede Anfrage hängen (Auth-Token, Organisationseinheit, Tracing-Daten), zentrale Fehlerbehandlung, alle Anfragen und Antworten in der Entwicklung protokollieren.

Andere Wege

  • GraphQL: eine Abfragesprache für APIs. Für Angular gibt es den Client Apollo (ng add apollo-angular).
  • WebSocket: Kommunikation in beide Richtungen über eine einzige TCP-Verbindung. Schnell, braucht aber besondere Behandlung auf beiden Seiten.

(Folie 295)

Widerspruch

Kurs: HttpClientModule importieren, Interceptors als Klassen über HTTP_INTERCEPTORS anmelden, der HttpClient nutzt XMLHttpRequest. Heute: Standalone-Apps nutzen provideHttpClient(), seit v21 ist der HttpClient standardmässig im Root-Injector verfügbar. Seit v22 nutzt er standardmässig die Fetch API (withXhr() für den alten Weg, dann aber ohne Upload-Fortschritt). Mit httpResource() (stabil seit v22) lassen sich Daten als Signal laden (Quelle - Recherche - Angular heute 2026). Funktionale Interceptors (withInterceptors([...])) sind heute üblich, das ist eine Einordnung von Claude.

Verwandt