Angular 20 im Jahr 2026: Resource API, httpResource und Interviewfragen
Angular 20 führt die Resource API und httpResource als signalbasierte Alternativen zu manuellen HttpClient-Subscriptions ein. Dieser Leitfaden behandelt alle drei Resource-Varianten, Zod-Validierung und häufige Interviewfragen.

Angular 20 stellt die Resource API und httpResource in den Mittelpunkt des signalbasierten Datenabrufs. Diese APIs ersetzen umständliche HttpClient-Subscription-Muster durch reaktive Primitiven, die Lade-, Fehler- und Ergebnis-Zustände automatisch verfolgen.
Die Resource API benennt request in params und loader in stream (für rxResource) um. Statuswerte sind jetzt String-Literale ('idle', 'loading', 'resolved', 'error', 'reloading', 'local') statt numerischer Enums. httpResource baut auf HttpClient auf und unterstützt Interceptors sowie Zod-Validierung direkt ab Werk.
Die drei Resource-Varianten in Angular 20
Angular 20 bietet drei Wege, um asynchrone Daten als Signals zu laden. Jede Variante zielt auf einen anderen Anwendungsfall ab, aber alle teilen dasselbe reaktive Modell: Abhängigkeiten deklarieren, einen Loader definieren und das Ergebnis über Signals konsumieren.
resource()arbeitet mit Promises. Ideal bei Verwendung vonfetch()oder jeder Promise-basierten API.rxResource()arbeitet mit Observables. Die richtige Wahl, wenn RxJS-Operatoren wiedebounceTime,retryoderswitchMapbenötigt werden.httpResource()umschließt AngularsHttpClientdirekt. Interceptors, Test-Utilities und Schema-Validierung funktionieren ohne zusätzliche Konfiguration.
Der entscheidende Unterschied zwischen httpResource und den anderen beiden: httpResource nutzt HttpClient intern, was bedeutet, dass bestehende Interceptors weiterhin funktionieren. Die ursprüngliche resource()-API umging HttpClient vollständig, was in Angular 19 ein wesentlicher Kritikpunkt war.
Ein Benutzerprofil mit resource() erstellen
Die resource()-Funktion akzeptiert eine params-Berechnung und eine loader-Funktion. Wenn sich Signals innerhalb von params ändern, wird der Loader automatisch erneut ausgeführt.
import { Component, signal, resource } from '@angular/core';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-profile',
template: `
@if (userResource.hasValue()) {
<h2>{{ userResource.value().name }}</h2>
<p>{{ userResource.value().email }}</p>
} @else if (userResource.isLoading()) {
<p>Loading profile...</p>
} @else if (userResource.error()) {
<p>Failed to load user</p>
}
`,
})
export class UserProfileComponent {
userId = signal(1);
// params produces the reactive dependency
// loader receives it and returns a Promise
userResource = resource<User, number>({
params: () => this.userId(),
loader: async ({ params: id, abortSignal }) => {
const res = await fetch(`/api/users/${id}`, { signal: abortSignal });
return res.json();
},
});
loadUser(id: number) {
this.userId.set(id); // triggers automatic refetch
}
}Der abortSignal-Parameter ermöglicht es Angular, laufende Anfragen abzubrechen, wenn sich userId ändert, bevor die vorherige Anfrage abgeschlossen ist. Das verhindert Race Conditions ohne manuelles Subscription-Management.
Reaktiver Datenabruf mit httpResource
httpResource eliminiert Boilerplate-Code, indem URL-Deklaration und HTTP-Ausführung in einem einzigen Aufruf kombiniert werden. Es gibt ein HttpResourceRef zurück, das value, isLoading, error, status und headers als Signals bereitstellt.
import { Component, signal, computed } from '@angular/core';
import { httpResource } from '@angular/common/http';
interface Product {
id: number;
name: string;
price: number;
category: string;
}
@Component({
selector: 'app-product-list',
template: `
@if (products.hasValue()) {
@for (product of products.value(); track product.id) {
<div class="product-card">
<h3>{{ product.name }}</h3>
<span>{{ product.price | currency }}</span>
</div>
}
} @else if (products.isLoading()) {
<p>Loading products...</p>
}
`,
})
export class ProductListComponent {
category = signal('electronics');
// httpResource re-fetches whenever category() changes
products = httpResource<Product[]>(() => ({
url: '/api/products',
params: { category: this.category() },
}));
filterByCategory(cat: string) {
this.category.set(cat); // pending request is cancelled, new one starts
}
}Die an httpResource übergebene Funktion gibt ein Request-Konfigurationsobjekt zurück. Angular verfolgt Signal-Lesevorgänge innerhalb dieser Funktion, sodass eine Änderung von category eine neue GET-Anfrage auslöst. Befindet sich bereits eine Anfrage im Flug, bricht Angular diese ab, bevor die neue gestartet wird.
httpResource ist für den Datenabruf (GET-Anfragen) konzipiert. Die Verwendung für POST-, PUT- oder DELETE-Operationen ist unsicher, da das Abbrechen von Anfragen Mutationen mitten in der Ausführung unterbrechen könnte. Für Schreiboperationen sollte HttpClient direkt verwendet oder Mutationen in eine Service-Methode eingebettet werden.
Schema-Validierung mit Zod und httpResource
API-Antworten externer Dienste können von den erwarteten Datenstrukturen abweichen. Die parse-Option von httpResource integriert Schema-Validierungsbibliotheken wie Zod, um Abweichungen zur Laufzeit zu erkennen, statt fehlerhafte Daten stillschweigend weiterzugeben.
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
import { z } from 'zod';
// Define the expected shape with Zod
const OrderSchema = z.object({
id: z.number(),
status: z.enum(['pending', 'shipped', 'delivered', 'cancelled']),
total: z.number().positive(),
items: z.array(z.object({
productId: z.number(),
quantity: z.number().int().positive(),
unitPrice: z.number().positive(),
})),
createdAt: z.string().datetime(),
});
type Order = z.infer<typeof OrderSchema>;
@Component({
selector: 'app-order',
template: `
@if (order.hasValue()) {
<h2>Order #{{ order.value().id }}</h2>
<p>Status: {{ order.value().status }}</p>
<p>Total: {{ order.value().total | currency }}</p>
} @else if (order.error()) {
<p>Invalid order data received</p>
}
`,
})
export class OrderComponent {
orderId = signal(42);
// parse validates the response before exposing it as a signal
order = httpResource<Order>(
() => `/api/orders/${this.orderId()}`,
{ parse: OrderSchema.parse }
);
}Wenn die API Daten zurückgibt, die nicht zum OrderSchema passen, wechselt die Resource in den 'error'-Status. Der Rückgabetyp der parse-Funktion bestimmt auch den TypeScript-Typ von value(), sodass Schema-Definitionen gleichzeitig als Laufzeit-Validatoren und Typ-Generatoren dienen.
rxResource mit Stream und Params in Angular 20
Angular 20 benennt loader in stream und request in params bei rxResource um. Diese Namensänderung orientiert sich an der Streaming-Semantik, die rxResource unterstützt. Die stream-Funktion erhält einen Observable-Kontext und muss ein Observable zurückgeben.
import { Component, signal } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
import { debounceTime, switchMap } from 'rxjs';
interface SearchResult {
id: number;
title: string;
excerpt: string;
}
@Component({
selector: 'app-search',
template: `
<input (input)="query.set($any($event.target).value)" placeholder="Search..." />
@if (results.isLoading()) {
<p>Searching...</p>
}
@if (results.hasValue()) {
@for (item of results.value(); track item.id) {
<div>{{ item.title }}</div>
}
}
`,
})
export class SearchComponent {
private http = inject(HttpClient);
query = signal('');
// params (was "request") provides the reactive input
// stream (was "loader") returns an Observable
results = rxResource<SearchResult[], string>({
params: () => this.query(),
stream: ({ params: q }) =>
this.http.get<SearchResult[]>('/api/search', {
params: { q },
}),
});
}Im Gegensatz zu httpResource bietet rxResource volle Kontrolle über die Observable-Pipeline. Operatoren wie debounceTime oder retry können innerhalb von stream verkettet werden. Für den häufigsten Fall (einzelne GET-Anfrage) erfordert httpResource jedoch weniger Code.
Bereit für deine Angular-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Status-Tracking: String-Literale ersetzen Enums
Angular 20 ändert ResourceStatus von einem numerischen Enum zu einem String-Union-Typ. Die sechs möglichen Werte bieten detaillierten Einblick in den Lebenszyklus der Resource:
| Status | Bedeutung |
|---|---|
| 'idle' | params hat undefined zurückgegeben — keine Anfrage gesendet |
| 'loading' | Erste Anfrage läuft |
| 'reloading' | Folge-Anfrage nach vorherigem Erfolg |
| 'resolved' | Daten in value() verfügbar |
| 'error' | Anfrage fehlgeschlagen — error() enthält den Fehler |
| 'local' | Wert lokal über .set() oder .update() gesetzt |
import { Component, signal, resource } from '@angular/core';
@Component({
selector: 'app-status-demo',
template: `
<p>Status: {{ data.status() }}</p>
@switch (data.status()) {
@case ('loading') { <spinner /> }
@case ('reloading') { <subtle-spinner /> }
@case ('resolved') { <data-table [rows]="data.value()" /> }
@case ('error') { <error-banner [error]="data.error()" /> }
@case ('idle') { <p>Select a filter to load data</p> }
}
`,
})
export class StatusDemoComponent {
filter = signal<string | undefined>(undefined);
data = resource({
params: () => this.filter(),
loader: async ({ params: f, abortSignal }) => {
const res = await fetch(`/api/data?filter=${f}`, { signal: abortSignal });
return res.json();
},
});
}Die Rückgabe von undefined aus params setzt den Status auf 'idle' und verhindert die Ausführung des Loaders. Dieses Muster eignet sich gut für bedingten Datenabruf — eine Aufforderung anzeigen, bis der Benutzer eine Eingabe macht, und dann die Daten laden.
Seit Angular 20 löst der Aufruf von value() auf einer Resource im 'error'-Status eine Laufzeit-Exception aus. Lesezugriffe sollten immer mit hasValue() abgesichert oder status() vor dem Zugriff auf value() geprüft werden. Dies ist eine Breaking Change gegenüber Angular 19, wo value() bei Fehlern undefined zurückgab.
Angular 20 httpResource Interviewfragen
Die Resource API wird zunehmend zum Standardthema bei Angular-Interviewfragen. Die folgenden Fragen prüfen echtes Verständnis jenseits oberflächlicher Vertrautheit mit der API.
F: Welches Problem löst httpResource, das resource() nicht löst?
resource() verwendet fetch() oder einen beliebigen Promise-basierten Loader und umgeht dabei Angulars HttpClient. Das bedeutet, dass Interceptors (für Auth-Tokens, Logging, Fehlerbehandlung) nicht greifen. httpResource nutzt intern HttpClient, sodass Interceptors, Test-Utilities (HttpTestingController) und Features wie withFetch() ohne zusätzliche Konfiguration funktionieren.
F: Wann sollte rxResource gegenüber httpResource bevorzugt werden?
rxResource bietet volle Observable-Kontrolle über seine stream-Funktion. Die Wahl fällt auf rxResource, wenn die Daten-Pipeline RxJS-Operatoren erfordert — Debouncing von Sucheingaben, Wiederholungsversuche mit exponentiellem Backoff oder die Kombination mehrerer Streams mit combineLatest. Für einfache GET-Anfragen benötigt httpResource weniger Code.
F: Wie geht Angular mit gleichzeitigen Anfragen um, wenn sich ein Signal schnell ändert?
Alle drei Resource-Varianten brechen laufende Anfragen ab, wenn params einen neuen Wert erzeugt. Bei httpResource und resource() bricht das AbortSignal den zugrundeliegenden Fetch ab. Bei rxResource kündigt Angular das vorherige Observable-Abonnement. Dies verhindert, dass veraltete Antworten aktuelle Daten überschreiben.
F: Wozu dient der 'local'-Status?
Der Aufruf von .set() oder .update() auf einer Resource ändert ihren Wert lokal, ohne den Loader auszulösen. Der Status wechselt zu 'local', was anzeigt, dass der aktuelle Wert nicht vom Server stammt. Dies unterstützt optimistische UI-Updates — die Oberfläche spiegelt die Änderung sofort wider, während eine separate Mutations-Anfrage parallel läuft.
F: Wie funktioniert die Zod-Integration mit httpResource?
Die parse-Option akzeptiert jede Funktion mit der Signatur (data: unknown) => T. Wenn die HTTP-Antwort eintrifft, leitet httpResource das geparste JSON durch parse, bevor value() gesetzt wird. Wenn parse einen Fehler wirft (z.B. ZodError), wechselt die Resource in den 'error'-Status. Der Rückgabetyp von parse bestimmt den TypeScript-Typ von value() und bietet so sowohl Laufzeitsicherheit als auch Compile-Zeit-Typen aus einer einzigen Schema-Definition.
Für einen tieferen Einblick in Angular Signals und deren Integration in das breitere Framework behandelt das Signals-Modul berechnete Signals, Effects und das Reaktivitätsmodell.
Migration von HttpClient-Subscriptions zu httpResource
Bestehende Angular-Anwendungen rufen Daten typischerweise mit HttpClient-Subscriptions in ngOnInit ab oder verwenden AsyncPipe mit Observables. Die Migration zu httpResource folgt einem vorhersehbaren Muster:
// BEFORE: manual subscription in ngOnInit
@Component({ /* ... */ })
export class BeforeComponent implements OnInit, OnDestroy {
private http = inject(HttpClient);
private destroy$ = new Subject<void>();
users: User[] = [];
loading = false;
error: string | null = null;
ngOnInit() {
this.loading = true;
this.http.get<User[]>('/api/users')
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (data) => { this.users = data; this.loading = false; },
error: (err) => { this.error = err.message; this.loading = false; },
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
// AFTER: httpResource handles lifecycle automatically
@Component({ /* ... */ })
export class AfterComponent {
users = httpResource<User[]>(() => '/api/users');
// No ngOnInit, no Subject, no manual unsubscribe
// Template uses users.value(), users.isLoading(), users.error()
}Die Migration beseitigt den gesamten Lifecycle-Management-Boilerplate. Die Bereinigung von Subscriptions erfolgt automatisch, wenn die Komponente zerstört wird. Lade- und Fehlerzustände sind in die Resource integriert — separate Boolean-Flags sind nicht mehr nötig.
Für Anwendungen, die bereits Standalone Components verwenden, ist die Migration unkompliziert: Die HttpClient-Injektion und Subscription-Logik wird durch eine einzige httpResource-Deklaration ersetzt.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Fazit
httpResourceersetzt manuelleHttpClient-Subscriptions durch eine einzige reaktive Deklaration, die Laden, Fehler und Abbruch automatisch handhabtresource()eignet sich für Promise-basierte APIs,rxResource()für Observable-Pipelines mit RxJS-Operatoren undhttpResource()für Standard-HTTP-Aufrufe mit Interceptor-Unterstützung- Angular 20 benennt
requestinparamsundloaderinstreambeirxResourceum — bestehender Code muss entsprechend aktualisiert werden - Statuswerte sind jetzt String-Literale (
'idle','loading','resolved','error','reloading','local') und ersetzen die numerischen Enums aus Angular 19 - Die
parse-Option vonhttpResourceintegriert Zod oder Valibot für Laufzeit-Schema-Validierung, die gleichzeitig TypeScript-Typen ableitet - Der Aufruf von
value()auf einer Resource im Fehlerstatus wirft in Angular 20 eine Exception — immer mithasValue()absichern oderstatus()vorab prüfen - Alle Resource-Varianten brechen laufende Anfragen automatisch ab, wenn sich Abhängigkeiten ändern, und verhindern so Race Conditions ohne manuelle Abbruchlogik
Tags
Teilen
Verwandte Artikel

Angular 19 Interviewfragen: Signals, SSR und unverzichtbare Konzepte
Die häufigsten Angular 19 Interviewfragen: Signals, inkrementelle Hydration, zoneless Change Detection und neue reaktive APIs mit Codebeispielen und erwarteten Antworten.

Angular 19 Zoneless: Performance und Change Detection ohne Zone.js
Umfassender technischer Leitfaden zur Zoneless Change Detection in Angular 19 und 20. Funktionsweise der Signal-basierten Reaktivitaet, Aktivierung von provideZonelessChangeDetection, Migration von Zone.js-abhaengigem Code, Reactive Forms im Zoneless-Modus, SSR mit PendingTasks und Performance-Benchmarks im direkten Vergleich.

Top 25 Angular-Interviewfragen: Vollständiger Leitfaden zum Erfolg
Die 25 häufigsten Angular-Interviewfragen 2026. Detaillierte Antworten, Codebeispiele und Tipps, um die Stelle als Angular-Entwickler zu sichern.