# 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.
- Published: 2026-05-30
- Updated: 2026-05-30
- Author: SharpSkill
- Tags: angular, typescript, resource-api, httpresource, signals
- Reading time: 12 min
---
Angular 20 stellt die [Resource API](https://angular.dev/guide/signals/resource) 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.
> **Was hat sich in Angular 20 geändert?**
>
> 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 von `fetch()` oder jeder Promise-basierten API.
- **`rxResource()`** arbeitet mit Observables. Die richtige Wahl, wenn RxJS-Operatoren wie `debounceTime`, `retry` oder `switchMap` benötigt werden.
- **`httpResource()`** umschließt Angulars `HttpClient` direkt. 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](https://angular.dev/guide/http/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.
```typescript
// user-profile.component.ts
import { Component, signal, resource } from '@angular/core';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-profile',
template: `
@if (userResource.hasValue()) {
{{ userResource.value().name }}
{{ userResource.value().email }}
} @else if (userResource.isLoading()) {
Loading profile...
} @else if (userResource.error()) {
Failed to load user
}
`,
})
export class UserProfileComponent {
userId = signal(1);
// params produces the reactive dependency
// loader receives it and returns a Promise
userResource = resource({
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.
```typescript
// product-list.component.ts
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) {
{{ product.name }}
{{ product.price | currency }}
}
} @else if (products.isLoading()) {
Loading products...
}
`,
})
export class ProductListComponent {
category = signal('electronics');
// httpResource re-fetches whenever category() changes
products = httpResource(() => ({
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 nur für Lesezugriffe**
>
> `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](https://zod.dev/), um Abweichungen zur Laufzeit zu erkennen, statt fehlerhafte Daten stillschweigend weiterzugeben.
```typescript
// order.component.ts
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;
@Component({
selector: 'app-order',
template: `
@if (order.hasValue()) {
Order #{{ order.value().id }}
Status: {{ order.value().status }}
Total: {{ order.value().total | currency }}
} @else if (order.error()) {
Invalid order data received
}
`,
})
export class OrderComponent {
orderId = signal(42);
// parse validates the response before exposing it as a signal
order = httpResource(
() => `/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.
```typescript
// search.component.ts
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: `
@if (results.isLoading()) {
}
}
`,
})
export class SearchComponent {
private http = inject(HttpClient);
query = signal('');
// params (was "request") provides the reactive input
// stream (was "loader") returns an Observable
results = rxResource({
params: () => this.query(),
stream: ({ params: q }) =>
this.http.get('/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.
## 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 |
```typescript
// status-demo.component.ts
import { Component, signal, resource } from '@angular/core';
@Component({
selector: 'app-status-demo',
template: `
}
}
`,
})
export class StatusDemoComponent {
filter = signal(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.
> **Zugriff auf value() im Fehlerstatus**
>
> 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](/blog/angular/angular-19-interview-questions-signals-ssr-must-know). 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](/technologies/angular/interview-questions/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:
```typescript
// BEFORE: manual subscription in ngOnInit
@Component({ /* ... */ })
export class BeforeComponent implements OnInit, OnDestroy {
private http = inject(HttpClient);
private destroy$ = new Subject();
users: User[] = [];
loading = false;
error: string | null = null;
ngOnInit() {
this.loading = true;
this.http.get('/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(() => '/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](/blog/angular/angular-standalone-components-migration-best-practices) verwenden, ist die Migration unkompliziert: Die `HttpClient`-Injektion und Subscription-Logik wird durch eine einzige `httpResource`-Deklaration ersetzt.
## Fazit
- `httpResource` ersetzt manuelle `HttpClient`-Subscriptions durch eine einzige reaktive Deklaration, die Laden, Fehler und Abbruch automatisch handhabt
- `resource()` eignet sich für Promise-basierte APIs, `rxResource()` für Observable-Pipelines mit RxJS-Operatoren und `httpResource()` für Standard-HTTP-Aufrufe mit Interceptor-Unterstützung
- Angular 20 benennt `request` in `params` und `loader` in `stream` bei `rxResource` um — 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 von `httpResource` integriert 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 mit `hasValue()` absichern oder `status()` vorab prüfen
- Alle Resource-Varianten brechen laufende Anfragen automatisch ab, wenn sich Abhängigkeiten ändern, und verhindern so Race Conditions ohne manuelle Abbruchlogik
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/de/blog/angular/angular-20-resource-api-httpresource-tutorial