# Angular 20 en 2026 : Resource API, httpResource et questions d'entretien > Angular 20 introduit httpResource et stabilise la Resource API pour la récupération de données fondée sur les signals. Un tutoriel pratique sur resource(), rxResource(), httpResource(), la validation Zod et les questions d'entretien courantes. - Published: 2026-05-30 - Updated: 2026-06-06 - Author: SharpSkill - Tags: angular, angular-20, resource-api, httpresource, signals, typescript, tutorial - Reading time: 10 min --- Angular 20 place la [Resource API](https://angular.dev/guide/signals/resource) et `httpResource` au cœur de la récupération de données fondée sur les signals. Ces API expérimentales remplacent les schémas de souscription verbeux de `HttpClient` par des primitives réactives qui suivent automatiquement les états de chargement, d'erreur et de résolution. > **Ce qui change dans Angular 20** > > La Resource API renomme `request` en `params` et `loader` en `stream` (pour `rxResource`). Les valeurs de statut sont désormais des littéraux de chaîne (`'idle'`, `'loading'`, `'resolved'`, `'error'`, `'reloading'`, `'local'`) au lieu d'énumérations numériques. `httpResource` s'appuie sur `HttpClient` et prend en charge nativement les interceptors et la validation Zod. ## Les trois variantes de Resource dans Angular 20 Angular 20 propose trois manières de charger des données asynchrones sous forme de signals. Chacune cible un cas d'usage différent, mais toutes partagent le même modèle réactif : déclarer les dépendances, définir un loader, puis consommer le résultat via des signals. - **`resource()`** fonctionne avec les Promises. Idéal pour `fetch()` ou toute API fondée sur les promesses. - **`rxResource()`** fonctionne avec les Observables. Le bon choix lorsque des opérateurs RxJS comme `debounceTime`, `retry` ou `switchMap` sont nécessaires. - **`httpResource()`** encapsule directement le `HttpClient` d'Angular. Les interceptors, les utilitaires de test et la validation de schéma fonctionnent sans configuration supplémentaire. La différence essentielle entre `httpResource` et les deux autres : `httpResource` s'appuie sur `HttpClient` en interne, ce qui signifie que les [interceptors](https://angular.dev/guide/http/interceptors) existants continuent de fonctionner. L'API `resource()` d'origine contournait totalement `HttpClient`, un point de friction majeur dans Angular 19. ## Construire un profil utilisateur avec resource() La fonction `resource()` accepte une fonction de calcul `params` et une fonction `loader`. Lorsque les signals présents dans `params` changent, le loader se réexécute automatiquement. ```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 } } ``` Le paramètre `abortSignal` permet à Angular d'annuler les requêtes en cours lorsque `userId` change avant que la requête précédente ne se termine. Cela évite les conditions de course sans gestion manuelle des souscriptions. ## Récupération réactive de données avec httpResource `httpResource` élimine le code répétitif en combinant la déclaration de l'URL et l'exécution HTTP en un seul appel. Il retourne un `HttpResourceRef` qui expose `value`, `isLoading`, `error`, `status` et `headers` sous forme de signals. ```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 } } ``` Plusieurs détails comptent ici. La fonction passée à `httpResource` retourne un objet de configuration de requête. Angular suit les lectures de signals à l'intérieur de cette fonction : modifier `category` déclenche donc une nouvelle requête GET. Si une requête est déjà en cours, Angular l'annule avant de lancer la nouvelle. > **httpResource est réservé à la lecture** > > `httpResource` est conçu pour la récupération de données (requêtes GET). L'utiliser pour des opérations POST, PUT ou DELETE est dangereux, car l'annulation d'une requête pourrait interrompre une mutation en cours. Pour les opérations d'écriture, utiliser directement `HttpClient` ou encapsuler les mutations dans une méthode de service. ## Validation de schéma avec Zod et httpResource Les réponses des services externes peuvent dévier de la forme attendue. L'option `parse` de `httpResource` intègre des bibliothèques de validation de schéma comme [Zod](https://zod.dev/) afin de détecter les écarts à l'exécution, au lieu de propager silencieusement des données corrompues. ```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 } ); } ``` Lorsque l'API retourne des données qui ne correspondent pas à `OrderSchema`, la resource passe au statut `'error'`. Le type de retour de la fonction `parse` détermine également le type TypeScript de `value()` : les définitions de schéma jouent donc un double rôle, validateurs à l'exécution et générateurs de types. ## rxResource avec stream et params dans Angular 20 Angular 20 renomme `loader` en `stream` et `request` en `params` dans `rxResource`. Ce changement aligne la nomenclature sur la sémantique de flux que `rxResource` prend en charge. La fonction `stream` reçoit un contexte d'Observable et doit retourner un Observable. ```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 }, }), }); } ``` Contrairement à `httpResource`, `rxResource` offre un contrôle total sur le pipeline d'Observable. Des opérateurs comme `debounceTime` ou `retry` peuvent être chaînés à l'intérieur de `stream`. En revanche, `httpResource` traite le cas le plus courant (une seule requête GET) avec moins de code. ## Suivi du statut : les littéraux de chaîne remplacent les énumérations Angular 20 transforme `ResourceStatus`, qui passe d'une énumération numérique à un type union de chaînes. Les six valeurs possibles offrent une vision fine du cycle de vie de la resource : | Statut | Signification | |---|---| | `'idle'` | `params` a retourné `undefined` — aucune requête émise | | `'loading'` | Première requête en cours | | `'reloading'` | Requête suivante après un succès précédent | | `'resolved'` | Données disponibles dans `value()` | | `'error'` | Échec de la requête — `error()` contient l'erreur | | `'local'` | Valeur définie localement via `.set()` ou `.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(); }, }); } ``` Retourner `undefined` depuis `params` fixe le statut à `'idle'` et empêche le loader de s'exécuter. Ce schéma convient bien à la récupération conditionnelle de données : afficher une invite tant que l'utilisateur n'a pas fourni d'entrée, puis charger les données. > **Accéder à value() en état d'erreur** > > Depuis Angular 20, appeler `value()` sur une resource au statut `'error'` lève une exception à l'exécution. Toujours protéger les lectures avec `hasValue()` ou vérifier `status()` avant d'accéder à `value()`. Il s'agit d'un changement cassant par rapport à Angular 19, où `value()` retournait `undefined` en cas d'erreur. ## Questions d'entretien Angular 20 sur httpResource La Resource API devient un sujet incontournable des [questions d'entretien Angular](/blog/angular/angular-19-interview-questions-signals-ssr-must-know). Voici des questions qui testent une compréhension réelle, au-delà d'une familiarité superficielle avec l'API. **Q : Quel problème `httpResource` résout-il que `resource()` ne résout pas ?** `resource()` utilise `fetch()` ou tout loader fondé sur une promesse, en contournant le `HttpClient` d'Angular. Les interceptors (jetons d'authentification, journalisation, gestion d'erreurs) ne s'appliquent donc pas. `httpResource` utilise `HttpClient` en interne : les interceptors, les utilitaires de test (`HttpTestingController`) et des fonctionnalités comme `withFetch()` fonctionnent sans configuration supplémentaire. **Q : Quand faut-il préférer `rxResource` à `httpResource` ?** `rxResource` offre un contrôle total sur l'Observable via sa fonction `stream`. Le choisir lorsque le pipeline de données nécessite des opérateurs RxJS : limiter une saisie de recherche, réessayer des requêtes échouées avec un backoff exponentiel, ou combiner plusieurs flux avec `combineLatest`. Pour de simples requêtes GET, `httpResource` demande moins de code. **Q : Comment Angular gère-t-il les requêtes concurrentes lorsqu'un signal change rapidement ?** Les trois variantes de resource annulent les requêtes en cours lorsque `params` produit une nouvelle valeur. Pour `httpResource` et `resource()`, l'`AbortSignal` annule le fetch sous-jacent. Pour `rxResource`, Angular se désabonne de l'Observable précédent. Cela empêche des réponses obsolètes d'écraser des données fraîches. **Q : À quoi sert le statut `'local'` ?** Appeler `.set()` ou `.update()` sur une resource modifie sa valeur localement sans déclencher le loader. Le statut passe à `'local'`, ce qui indique que la valeur courante ne provient pas du serveur. Cela facilite les mises à jour optimistes de l'interface : l'UI reflète le changement immédiatement pendant qu'une requête de mutation distincte s'exécute. **Q : Comment fonctionne l'intégration de Zod avec `httpResource` ?** L'option `parse` accepte toute fonction de signature `(data: unknown) => T`. À l'arrivée de la réponse HTTP, `httpResource` passe le JSON analysé à travers `parse` avant de définir `value()`. Si `parse` lève une exception (par exemple `ZodError`), la resource passe au statut `'error'`. Le type de retour de `parse` détermine le type TypeScript de `value()`, offrant à la fois sécurité à l'exécution et types à la compilation à partir d'une seule définition de schéma. Pour approfondir les [signals Angular](/technologies/angular/interview-questions/angular-signals) et leur intégration dans le framework au sens large, le module sur les signals couvre les computed signals, les effects et le modèle de réactivité. ## Migrer des souscriptions HttpClient vers httpResource Les applications Angular existantes récupèrent généralement des données via des souscriptions `HttpClient` dans `ngOnInit`, ou utilisent l'`AsyncPipe` avec des Observables. La migration vers `httpResource` suit un schéma prévisible : ```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() } ``` La migration supprime le code répétitif de gestion du cycle de vie. Le nettoyage des souscriptions se fait automatiquement à la destruction du composant. Les états de chargement et d'erreur sont intégrés à la resource : plus besoin de drapeaux booléens séparés. Pour les applications utilisant déjà les [composants standalone](/blog/angular/angular-standalone-components-migration-best-practices), la migration est directe : remplacer l'injection de `HttpClient` et la logique de souscription par une unique déclaration `httpResource`. ## Conclusion - `httpResource` remplace les souscriptions manuelles à `HttpClient` par une seule déclaration réactive qui gère automatiquement le chargement, l'erreur et l'annulation - Utiliser `resource()` pour les API fondées sur les promesses, `rxResource()` pour les pipelines d'Observables avec opérateurs RxJS, et `httpResource()` pour les appels HTTP standard avec prise en charge des interceptors - Angular 20 renomme `request` en `params` et `loader` en `stream` dans `rxResource` — mettre à jour le code existant en conséquence - Les valeurs de statut sont désormais des littéraux de chaîne (`'idle'`, `'loading'`, `'resolved'`, `'error'`, `'reloading'`, `'local'`), remplaçant les énumérations numériques d'Angular 19 - L'option `parse` de `httpResource` intègre Zod ou Valibot pour une validation de schéma à l'exécution qui pilote aussi les types TypeScript - Appeler `value()` sur une resource en état d'erreur lève une exception dans Angular 20 — toujours protéger avec `hasValue()` ou vérifier `status()` d'abord - Toutes les variantes de resource annulent automatiquement les requêtes en cours lorsque les dépendances changent, évitant les conditions de course sans logique d'annulation manuelle --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/fr/blog/angular/angular-20-resource-api-httpresource-tutorial