Angular Resource API en httpResource: Volledige gids (Stabiel in Angular 22)
Angular's Resource API en httpResource zijn stabiel sinds Angular 22. Deze gids behandelt resource(), rxResource(), httpResource(), de nieuwe chain() helper voor afhankelijke resources, Zod-validatie en veelgestelde sollicitatievragen.

Angular's Resource API en httpResource bieden signal-gebaseerde data-ophaling die laad-, fout- en opgeloste toestanden automatisch bijhoudt. Geïntroduceerd in Angular 20, werden deze API's stabiel in Angular 22, ter vervanging van omslachtige HttpClient-subscription-patronen door reactieve primitieven.
De Resource API (resource(), rxResource(), httpResource()) is gepromoveerd van experimenteel naar stabiel in Angular 22 (juni 2026). De params en stream naamgeving, string literal statussen en de nieuwe chain() helper voor afhankelijke resources zijn allemaal productierijp. Bij een upgrade van Angular 20 of 21 blijft de API-interface compatibel.
De drie Resource-varianten
Angular biedt drie manieren om asynchrone data als signals te laden. Elke variant richt zich op een ander gebruiksscenario, maar ze delen allemaal hetzelfde reactieve model: afhankelijkheden declareren, een loader definiëren en het resultaat via signals consumeren.
resource()werkt met Promises. Ideaal bij gebruik vanfetch()of een andere Promise-gebaseerde API.rxResource()werkt met Observables. De juiste keuze wanneer RxJS-operators zoalsdebounceTime,retryofswitchMapnodig zijn.httpResource()omhult Angular'sHttpClientrechtstreeks. Interceptors, test-utilities en schemavalidatie werken zonder extra configuratie.
Het belangrijkste verschil tussen httpResource en de andere twee: httpResource gebruikt HttpClient intern, wat betekent dat bestaande interceptors blijven werken. De oorspronkelijke resource() API omzeilde HttpClient volledig, wat een beperking was in Angular 19.
Een gebruikersprofiel bouwen met resource()
De resource()-functie accepteert een params-berekening en een loader-functie. Wanneer signals binnen params veranderen, wordt de loader automatisch opnieuw uitgevoerd.
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
}
}De abortSignal-parameter stelt Angular in staat om lopende verzoeken te annuleren wanneer userId verandert voordat het vorige verzoek is voltooid. Dit voorkomt race conditions zonder handmatig subscription-beheer.
Reactieve data-ophaling met httpResource
httpResource elimineert boilerplate-code door URL-declaratie en HTTP-uitvoering te combineren in één enkele aanroep. Het retourneert een HttpResourceRef dat value, isLoading, error, status en headers als signals beschikbaar stelt.
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
}
}De functie die aan httpResource wordt doorgegeven, retourneert een request-configuratieobject. Angular volgt signal-leesbewerkingen binnen deze functie, dus het wijzigen van category triggert een nieuw GET-verzoek. Als er al een verzoek onderweg is, annuleert Angular dit voordat het nieuwe wordt gestart.
httpResource is ontworpen voor data-ophaling (GET-verzoeken). Het gebruiken voor POST-, PUT- of DELETE-operaties is onveilig, omdat het annuleren van verzoeken mutaties halverwege kan afbreken. Gebruik voor schrijfoperaties HttpClient rechtstreeks of verpak mutaties in een service-methode.
Resources koppelen met chain()
Angular 22 introduceerde de chain() helper voor het laden van afhankelijke resources. Wanneer één resource afhankelijk is van de waarde van een andere, propageert chain() automatisch laad- en foutstatussen.
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
interface User {
id: number;
name: string;
authorId: string;
}
interface Post {
id: number;
title: string;
content: string;
}
@Component({
selector: 'app-user-posts',
template: \`
@if (postsResource.isLoading()) {
<p>Loading...</p>
} @else if (postsResource.hasValue()) {
<h2>Posts by {{ userResource.value().name }}</h2>
@for (post of postsResource.value(); track post.id) {
<article>
<h3>{{ post.title }}</h3>
</article>
}
} @else if (postsResource.error()) {
<p>Failed to load posts</p>
}
\`,
})
export class UserPostsComponent {
userId = signal(1);
userResource = httpResource<User>(() => \`/api/users/\${this.userId()}\`);
// chain() propagates userResource's status to postsResource
postsResource = httpResource<Post[]>({
params: ({ chain }) => {
const user = chain(this.userResource);
return { url: '/api/posts', params: { authorId: user.authorId } };
},
});
}chain(userResource) retourneert niet alleen de waarde. Terwijl userResource laadt, rapporteert ook postsResource de laadstatus en voert zijn loader niet uit. Als userResource een fout geeft, gaat postsResource over naar foutstatus met een ResourceDependencyError die de oorspronkelijke fout bevat.
Dit vervangt het RxJS-patroon van geneste switchMap-aanroepen door expliciete, standaard correcte statuspropagatie.
Schemavalidatie met Zod en httpResource
API-responses van externe diensten kunnen afwijken van de verwachte datastructuren. De parse-optie van httpResource integreert schemavalidatiebibliotheken zoals Zod om afwijkingen tijdens runtime te detecteren in plaats van corrupte data stilzwijgend door te geven.
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 }
);
}Wanneer de API data retourneert die niet overeenkomt met OrderSchema, schakelt de resource over naar de 'error'-status. Het retourtype van de parse-functie bepaalt ook het TypeScript-type van value(), waardoor schemadefinities zowel als runtime-validators als type-generatoren fungeren.
rxResource met Stream en Params
Angular hernoemt loader naar stream en request naar params bij rxResource. Deze naamswijziging sluit aan bij de streaming-semantiek die rxResource ondersteunt. De stream-functie ontvangt een Observable-context en moet een Observable retourneren.
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((.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 },
}),
});
}In tegenstelling tot httpResource biedt rxResource volledige controle over de Observable-pipeline. Operators zoals debounceTime of retry kunnen binnen stream worden gekoppeld. Voor het meest voorkomende scenario (enkel GET-verzoek) vereist httpResource echter minder code.
Klaar om je Angular gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Statustracking: string-literals vervangen enums
ResourceStatus is een string-union-type. De zes mogelijke waarden bieden gedetailleerd inzicht in de levenscyclus van de resource:
| Status | Betekenis |
|---|---|
'idle' | params retourneerde undefined, geen verzoek verzonden |
'loading' | Eerste verzoek in uitvoering |
'reloading' | Volgend verzoek na een eerder succes |
'resolved' | Data beschikbaar in value() |
'error' | Verzoek mislukt, error() bevat de fout |
'local' | Waarde lokaal ingesteld via .set() of .update() |
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();
},
});
}Het retourneren van undefined vanuit params zet de status op 'idle' en voorkomt dat de loader wordt uitgevoerd. Dit patroon werkt goed voor voorwaardelijke data-ophaling: een prompt tonen totdat de gebruiker invoer geeft, en dan de data laden.
Het aanroepen van value() op een resource in 'error'-status gooit een runtime-exceptie. Leesbewerkingen moeten altijd worden beschermd met hasValue() of door status() te controleren voordat value() wordt benaderd. Dit is een wijziging ten opzichte van Angular 19, waar value() bij fouten undefined retourneerde.
Angular httpResource sollicitatievragen
De Resource API wordt steeds vaker een standaardonderwerp bij Angular-sollicitatievragen. De volgende vragen toetsen een echt begrip dat verder gaat dan oppervlakkige bekendheid met de API.
V: Welk probleem lost httpResource op dat resource() niet oplost?
resource() gebruikt fetch() of een andere Promise-gebaseerde loader en omzeilt daarbij Angular's HttpClient. Dit betekent dat interceptors (voor auth-tokens, logging, foutafhandeling) niet worden toegepast. httpResource gebruikt intern HttpClient, waardoor interceptors, test-utilities (HttpTestingController) en functies zoals withFetch() zonder extra configuratie werken.
V: Wanneer heeft rxResource de voorkeur boven httpResource?
rxResource biedt volledige Observable-controle via de stream-functie. De keuze valt op rxResource wanneer de datapipeline RxJS-operators vereist: debouncing van zoekinvoer, herhaalpogingen met exponentieel backoff of het combineren van meerdere streams met combineLatest. Voor eenvoudige GET-verzoeken vereist httpResource minder code.
V: Hoe gaat Angular om met gelijktijdige verzoeken wanneer een signal snel verandert?
Alle drie de Resource-varianten annuleren lopende verzoeken wanneer params een nieuwe waarde produceert. Bij httpResource en resource() annuleert het AbortSignal het onderliggende fetch-verzoek. Bij rxResource meldt Angular zich af van het vorige Observable. Dit voorkomt dat verouderde responses actuele data overschrijven.
V: Wat is het doel van de 'local'-status?
Het aanroepen van .set() of .update() op een resource wijzigt de waarde lokaal zonder de loader te activeren. De status gaat over naar 'local', wat aangeeft dat de huidige waarde niet van de server afkomstig is. Dit ondersteunt optimistische UI-updates: de interface weerspiegelt de wijziging onmiddellijk terwijl een apart mutatieverzoek parallel wordt uitgevoerd.
V: Hoe werkt de Zod-integratie met httpResource?
De parse-optie accepteert elke functie met de signatuur (data: unknown) => T. Wanneer de HTTP-response binnenkomt, stuurt httpResource de geparseerde JSON door parse voordat value() wordt ingesteld. Als parse een fout gooit (bijv. ZodError), gaat de resource over naar de 'error'-status. Het retourtype van parse bepaalt het TypeScript-type van value(), wat zowel runtime-veiligheid als compilatietijdtypes oplevert vanuit één enkele schemadefinitie.
V: Hoe gaat chain() om met fouten van upstream resources?
Bij het gebruik van chain(upstreamResource) in de params-functie van een resource, voert de afhankelijke resource zijn loader niet uit als de upstream resource aan het laden is, idle is of in foutstatus staat. Als de upstream resource een fout geeft, gaat de afhankelijke resource over naar foutstatus met een ResourceDependencyError. Deze fout bevat de dependency (de upstream resource) en cause (de daadwerkelijke upstream fout), waardoor onderscheid gemaakt kan worden tussen "mijn verzoek is mislukt" en "het verzoek van mijn afhankelijkheid is mislukt".
Voor een diepgaandere behandeling van Angular Signals en hoe deze integreren met het bredere framework, behandelt de signals-gids berekende signals, effects en het reactiviteitsmodel.
Migratie van HttpClient-subscriptions naar httpResource
Bestaande Angular-applicaties halen data doorgaans op met HttpClient-subscriptions in ngOnInit of gebruiken AsyncPipe met Observables. De migratie naar httpResource volgt een voorspelbaar patroon:
// 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()
}De migratie elimineert alle lifecycle-management boilerplate. Het opschonen van subscriptions gebeurt automatisch wanneer het component wordt vernietigd. Laad- en fouttoestanden zijn ingebouwd in de resource, aparte boolean-vlaggen zijn niet meer nodig.
Voor applicaties die al Standalone Components gebruiken, is de migratie eenvoudig: vervang de HttpClient-injectie en subscription-logica door één enkele httpResource-declaratie.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Bronnen
- Angular Resource API documentatie — officiële gids voor resource(), rxResource() en httpResource()
- What's new in Angular 22.0 — Ninja Squad coverage van de stabiele Resource API en chain() helper
- Angular HTTP interceptors gids — hoe interceptors werken met httpResource
Belangrijkste punten over Angular Resource API
httpResourcevervangt handmatigeHttpClient-subscriptions door één enkele reactieve declaratie die laden, fouten en annulering automatisch afhandelt- Gebruik
resource()voor Promise-gebaseerde API's,rxResource()voor Observable-pipelines met RxJS-operators enhttpResource()voor standaard HTTP-aanroepen met interceptor-ondersteuning - De
chain()helper (Angular 22+) maakt het laden van afhankelijke resources mogelijk met automatische statuspropagatie; als de upstream faalt, krijgt de afhankelijke eenResourceDependencyError - Statuswaarden zijn string-literals (
'idle','loading','resolved','error','reloading','local') - De
parse-optie vanhttpResourceintegreert Zod of Valibot voor runtime-schemavalidatie die tevens TypeScript-types genereert - Het aanroepen van
value()op een resource in foutstatus gooit een exceptie; altijd beschermen methasValue()ofstatus()vooraf controleren - Alle Resource-varianten annuleren lopende verzoeken automatisch wanneer afhankelijkheden veranderen, waardoor race conditions worden voorkomen zonder handmatige annuleringslogica
Zie jij de bug in Angular?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 13 oktober 2026
Tags
Delen
Gerelateerde artikelen

Angular Control Flow Syntax in 2026: @if, @for, @switch en Interviewvragen
Uitgebreide gids over de nieuwe Angular Control Flow Syntax met @if, @for en @switch. Performance-optimalisaties, Signal-integratie en veelgestelde interviewvragen voor Angular-ontwikkelaars.

RxJS in Angular 2026: operators, Subjects en Signals-interop
RxJS in Angular 2026: de operators, Subjects en Signals-interop-patronen die Angular-ontwikkelaars in productie gebruiken, plus de meest voorkomende sollicitatievragen.

Angular Signals en Computed in 2026: Fijnkorrelige Reactiviteit en Sollicitatievragen
Een diepgaande gids over Angular Signals, Computed Signals en het reactieve model in Angular 20+. Bevat best practices, RxJS-interoperabiliteit en veelgestelde technische sollicitatievragen.