Angular 20 in 2026: Resource API, httpResource en sollicitatievragen
Angular 20 introduceert de Resource API en httpResource als signal-gebaseerde alternatieven voor handmatige HttpClient-subscriptions. Deze handleiding behandelt alle drie Resource-varianten, Zod-validatie en veelgestelde sollicitatievragen.

Angular 20 plaatst de Resource API en httpResource centraal in signal-gebaseerde data-ophaling. Deze API's vervangen omslachtige HttpClient-subscription-patronen door reactieve primitieven die laad-, fout- en opgeloste toestanden automatisch bijhouden.
De Resource API hernoemt request naar params en loader naar stream (voor rxResource). Statuswaarden zijn nu string-literals ('idle', 'loading', 'resolved', 'error', 'reloading', 'local') in plaats van numerieke enums. httpResource bouwt voort op HttpClient en ondersteunt interceptors en Zod-validatie standaard.
De drie Resource-varianten in Angular 20
Angular 20 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 groot pijnpunt 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
}
}Een aantal details zijn hier van belang. 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.
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 in Angular 20
Angular 20 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($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 },
}),
});
}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
Angular 20 wijzigt ResourceStatus van een numeriek enum naar 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.
Vanaf Angular 20 gooit het aanroepen van value() op een resource in 'error'-status een runtime-exceptie. Leesbewerkingen moeten altijd worden beschermd met hasValue() of door status() te controleren voordat value() wordt benaderd. Dit is een breaking change ten opzichte van Angular 19, waar value() bij fouten undefined retourneerde.
Angular 20 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.
Voor een diepere duik in Angular Signals en hoe deze integreren met het bredere framework, behandelt de signals-module 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.
Conclusie
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 - Angular 20 hernoemt
requestnaarparamsenloadernaarstreambijrxResource— pas bestaande code dienovereenkomstig aan - Statuswaarden zijn nu string-literals (
'idle','loading','resolved','error','reloading','local'), ter vervanging van de numerieke enums uit Angular 19 - 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 in Angular 20 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
Tags
Delen
Gerelateerde artikelen

Angular 19 sollicitatievragen: Signals, SSR en onmisbare concepten
De meest voorkomende Angular 19 sollicitatievragen: Signals, incrementele hydration, zoneless change detection en nieuwe reactieve API's met codevoorbeelden en verwachte antwoorden.

Angular 19 Zoneless: Performance en Change Detection zonder Zone.js
Technische gids over Zoneless Change Detection in Angular 19 en 20. Werking van Signal-gebaseerde reactiviteit, activering van provideZonelessChangeDetection, migratieproblemen met setTimeout en Reactive Forms, SSR zonder Zone.js en prestatiebenchmarks.

Top 25 Angular Sollicitatievragen: Complete Gids voor Succes
De 25 meest gestelde Angular sollicitatievragen in 2026. Uitgebreide antwoorden, codevoorbeelden en tips om de Angular developer-rol binnen te halen.