# 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. - Published: 2026-05-30 - Updated: 2026-05-30 - Author: SharpSkill - Tags: angular, typescript, resource-api, httpresource, signals - Reading time: 12 min --- Angular 20 plaatst de [Resource API](https://angular.dev/guide/signals/resource) 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. > **Wat is er veranderd in Angular 20?** > > 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 van `fetch()` of een andere Promise-gebaseerde API. - **`rxResource()`** werkt met Observables. De juiste keuze wanneer RxJS-operators zoals `debounceTime`, `retry` of `switchMap` nodig zijn. - **`httpResource()`** omhult Angular's `HttpClient` rechtstreeks. 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](https://angular.dev/guide/http/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. ```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 } } ``` 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. ```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 } } ``` 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 alleen voor leesbewerkingen** > > `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](https://zod.dev/) om afwijkingen tijdens runtime te detecteren in plaats van corrupte data stilzwijgend door te geven. ```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 } ); } ``` 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. ```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 }, }), }); } ``` 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. ## 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()` | ```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(); }, }); } ``` 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. > **Toegang tot value() in foutstatus** > > 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](/blog/angular/angular-19-interview-questions-signals-ssr-must-know). 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](/technologies/angular/interview-questions/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: ```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() } ``` 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](/blog/angular/angular-standalone-components-migration-best-practices) gebruiken, is de migratie eenvoudig: vervang de `HttpClient`-injectie en subscription-logica door één enkele `httpResource`-declaratie. ## Conclusie - `httpResource` vervangt handmatige `HttpClient`-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 en `httpResource()` voor standaard HTTP-aanroepen met interceptor-ondersteuning - Angular 20 hernoemt `request` naar `params` en `loader` naar `stream` bij `rxResource` — 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 van `httpResource` integreert 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 met `hasValue()` of `status()` vooraf controleren - Alle Resource-varianten annuleren lopende verzoeken automatisch wanneer afhankelijkheden veranderen, waardoor race conditions worden voorkomen zonder handmatige annuleringslogica --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/angular/angular-20-resource-api-httpresource-tutorial