# 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()) {

Searching...

} @if (results.hasValue()) { @for (item of results.value(); track item.id) {
{{ item.title }}
} } `, }) 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: `

Status: {{ data.status() }}

@switch (data.status()) { @case ('loading') { } @case ('reloading') { } @case ('resolved') { } @case ('error') { } @case ('idle') {

Select a filter to load data

} } `, }) 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