Récupérer des données avec "httpResource()"

Récupérer des données avec "httpResource()"

Loïc Boutter (lazybobcat)
Loïc Boutter (lazybobcat)

Dans l’article précédent, nous avons utilisé la fonction resource() mise à disposition depuis Angular 19 afin d’avoir accès à des données asynchrones de façon réactive (et sans utiliser RxJs).

Depuis Angular 19.2, nous avons également deux outils supplémentaires à disposition (en “developer preview” au moment de la rédaction de cet article) : httpResource() et rxResource() (dont nous ne parlerons pas ici).

httpResource, comment ça fonctionne ?

Alors que resource() permet de rendre n’importe quelle source de données asynchrone réactive, il est très généraliste et nécessite de lui passer différentes options ou services.

La plupart du temps sur nos applications, nous avons besoin d’effectuer des requêtes HTTP afin de récupérer les données nécessaires à son fonctionnement. C’est même souvent la principale (voire l’unique) source de données asynchrones. Afin de faciliter la déclaration d’une resource() HTTP, Angular a introduit httpResource().

Dans cet article comme le précédent, nous prendrons pour exemple une petite application permettant de charger les données d’un Pokémon depuis une API (via une requête HTTP). Utilisons httpResource() plutôt que resource() pour la récupération des données :

Définir une Resource HTTP
selectedPokemon = signal(1);
query = httpResource<Pokemon>(
    () => `https://tyradex.vercel.app/api/v1/pokemon/${this.selectedPokemon()}`
);

Le code est très simple : httpResource() prend en paramètre une fonction utilisant un signal, similaire au paramètre de computed(), et renvoyant l’URL sur laquelle effectuer la requête. Lorsque le signal change, la requête est ré-exécutée. httpResource utilisera le service HttpClient comme loader et effectuera par défaut une requête GET. Si le type de la réponse HTTP n’est pas précisé, cela sera du JSON. L’utilisation d’ HttpClient permet également l’utilisation automatique des différents intercepteurs existants.

httpResource() est plus succinct que resource()
selectedPokemon = signal(1);
- query = resource({
-   request: () => ({ pokedexId: this.selectedPokemon() }),
-   loader: ({ request }) =>
-     lastValueFrom(
-       this.#httpClient.get<Pokemon>(
-         `https://tyradex.vercel.app/api/v1/pokemon/${request.pokedexId}`
-       )
-     ),
+ query = httpResource<Pokemon>(
+     () => `https://tyradex.vercel.app/api/v1/pokemon/${this.selectedPokemon()}`
);

Avoir la main sur la requête HTTP

Si vous avez besoin de plus d’options pour la requête HTTP, vous pouvez également passer un objet en paramètre à httpResource(), par exemple :

Définir une Resource HTTP avec plus d'options
query = httpResource(() => ({
    url: `https://tyradex.vercel.app/api/v1/pokemon/${this.selectedPokemon()}`,
    method: 'GET',
    headers: {
        'X-My-Custom-Header': 'my-value',
    },
    params: {
        'shiny': 'true',
    },
    reportProgress: true,
    withCredentials: true,
    transferCache: true,
}));

Avec cette méthode, il est possible d’utiliser une autre méthode HTTP que GET, cependant les Resource ne sont pas faites pour modifier les données sur le serveur. Pour la création ou la modification de la ressource sur le serveur, continuez d’utiliser HttpClient directement.

Méta-données de la réponse HTTP

En plus des signaux exposés par resource() (value(), status(), isLoading() et error()), httpResource ajoute les signaux suivants :

  • headers() : retourne les “headers” HTTP de la réponse.
  • statusCode() : retourne le code de retour HTTP.
  • progress() : retourne la progression de la requête (le nombre de bytes chargés ou téléversés), si reportProgress est défini à true.

Typage de la valeur et type de la réponse HTTP

Par défaut, httpResource part du principe que le serveur distant renverra le résultat sous forme d’un JSON. Comme avec HttpClient, vous pouvez fournir un type à la fonction pour récupérer un objet de ce type en value(). Mais attention, comme avec HttpClient aucune validation n’est effectuée sur la conformité de la ressource par rapport au type donné.

// query.value() sera de type "Pokemon"
query = httpResource<Pokemon>(
    () => ...
);

Si le type de la réponse HTTP n’est pas du JSON, plusieurs méthodes dédiées sont disponibles sur httpResource :

httpResource.text( ... ); // retourne du texte dans value()
httpResource.blob( ... ); // retourne un Blob (fichier) dans value()
httpResource.arrayBuffer( ... ); // retourne un ArrayBuffer dans value()

Valider le schéma de la ressource

Et si on souhaite s’assurer que les données retournées respectent un “schéma” spécifique ? Il n’existe pas de service de validation de schéma directement intégré à Angular, néanmoins il existe des modules très utilisés dans l’écosystème JavaScript tel que Zod.

httpResource met à disposition une façon de valider le schéma des données avec n’importe quel module. Pour cela on peut passer un second paramètre à httpResource(), qui est un objet ayant un attribut parse. Par exemple, avec Zod :

Validation du schéma avec Zod
const pokemonSchema = z.object({
    name: z.object({
        fr: z.string(),
    }),
    sprites: z.object({
        regular: z.string(),
    }),
});
type Pokemon = z.infer<typeof pokemonSchema>;
 
// ...
 
selectedPokemon = signal(1);
query = httpResource<Pokemon>(
    () => `https://tyradex.vercel.app/api/v1/pokemon/${this.selectedPokemon()}`,
    { parse: pokemonSchema.parse }
);

Si la ressource ne respecte pas le schéma indiqué, une erreur sera enregistrée dans query.error() !

Liens et exemple complet

Vous pouvez retrouver l’exemple complet sur Stackblitz.

Voici également quelques liens vers des sources de documentation :

Retour aux articles