Aller au contenu
BackNode.jsTips

Les intercepteurs Axios

Explorons les intercepteurs, l'une des fonctionnalités les plus puissantes d'Axios, et utilisons-les à travers un exemple pratique.

Image by Talha Khalil / Pixabay

Axios, une bibliothèque JavaScript populaire, offre un ensemble complet de fonctionnalités pour effectuer des requêtes HTTP. L'une de ses fonctionnalités est celle des intercepteurs, qui permettent d'intercepter et de transformer les requêtes et réponses. Ils permettent donc de centraliser la logique de gestion des appels HTTP, rendant le code plus clair et plus facile à maintenir.

Mais avant…

Avant d'implémenter les intercepteurs, il faut mettre en place un service qui va accepter nos requêtes et nous répondre. Il existe des milliers de manières pour mettre en place une API, vous pouvez en instancier une avec votre framework préféré.

Pour ma part, j'opte une image Docker kong/httpbin qui va instancier un service à l'adresse http://localhost:2137/.

$ docker pull kong/httpbin
$ docker run -d --name=httpbin -p 2137:80 kong/httpbin

Cette image Docker contient beaucoup de routes, je vais en utiliser certaines pour obtenir des requêtes réussies et d'autres qui échouent.

Si, à la fin de l'article, vous ne souhaitez pas conserver httpbin, vous pouvez lancer ces deux commandes qui suppriment le conteneur et l'image.

$ docker rm --force httpbin
$ docker rmi kong/httpbin

L'API est disponible et prête à être utilisée, on peut tester de l'appeler avec le module axios.

'use strict'
const axios = require('axios');

const instance = axios.create({
    baseURL: "http://localhost:2137",
    timeout: 1000
});

const makeRequest = (url, method) => {
    instance({ url: url, method: method })
        .then((response) => { console.log(`Response : ${JSON.stringify(response.data)}`); })
        .catch((error) => { console.error(`Error : ${error.message}`); });
};

makeRequest('/json', 'get');		// Retourne un document JSON
makeRequest('/delay/10', 'post');	// Retourne une réponse différée de 10 secondes.

intercept.js

En exécutant le programme on obtient ceci et ça correspond au comportement attendu. On reçoit un document JSON avec la route /json et une erreur se produit car le timeout d'une seconde est atteint sur la route /delay/10.

$ node intercept.js
Response : {"slideshow":{"author":"Yours Truly","date":"date of publication","slides":[{"title":"Wake up to WonderWidgets!","type":"all"},{"items":["Why <em>WonderWidgets</em> are great","Who <em>buys</em> WonderWidgets"],"title":"Overview","type":"all"}],"title":"Sample Slide Show"}}
Error : timeout of 1000ms exceeded

Tout fonctionne correctement, on peut s'attaquer aux intercepteurs.

Maintenant, codons !

Les intercepteurs interceptent les requêtes et les réponses. Ils se placent entre l'utilisateur et l'appel HTTP. Les intercepteurs de requêtes vont intervenir avant que la requête ne soit envoyée, tandis que les intercepteurs de réponses manipulent la réponse avant qu'elle n'atteigne l'utilisateur (dans le then() ou dans le catch()).

En se basant sur l'instance axios que nous avons créée, voici comment déclarer les intercepteurs.

const axios = require('axios');

const instance = axios.create({
    baseURL: `http://localhost:2137`,
    timeout: 1000
});

const requestHandler = (config) => {
    return config;
};
const responseHandler = (response) => {
    return response;
};
const requestErrorHandler = (error) => {
    return Promise.reject(error);
};
const responseErrorHandler = (error) => {
    return Promise.reject(error);
};

// Ajouter un intercepteur de requêtes
instance.interceptors.request.use(
    // Exécuter quelque chose avant l'envoi de la requête
    requestHandler,
    // Gérer l'erreur provoquée par la requête
    requestErrorHandler
    );

// Ajouter un intercepteur de réponses
instance.interceptors.response.use(
    // Manipuler la réponse réussie (le code HTTP est dans les 2xx)
    responseHandler, 
    // Gérer l'erreur provoquée par la réponse (code HTTP en dehors des 2xx)
    responseErrorHandler
    );

intercept.js

On appelle la méthode use sur les deux types d'intercepteurs, à savoir instance.interceptors.request et instance.interceptors.response. La méthode prend deux paramètres qui sont deux fonctions. La première va manipuler la requête ou la réponse, le seconde va se charger de l'erreur liée à la requête ou à la réponse. Dans tous les cas, les intercepteurs retournent l'élément afin de l'envoyer au serveur ou à l'appelant.

Regardons avec trois cas d'usage ce qu'on peut faire avec ces objets config, error et response.

Logging

L'exemple le plus simple est d'afficher ce qui se passe, en utilisant la console.

const responseHandler = (response) => {
    console.log(`Status =] : ${response.status}`);
    return response;
};

const responseErrorHandler = (error) => {
    console.error(`Status =[ : ${error.response.status}`);
    return Promise.reject(error);
};

instance.interceptors.response.use(responseHandler, responseErrorHandler);

makeRequest('/uuid', 'get');
makeRequest('/status/404', 'post');

intercept.js

On voit ici que la réponse est d'abord traitée par l'intercepteur avant d'être transmise à l'utilisateur.

$ node intercept.js
Status =] : 200
Response : {"uuid":"55a14df0-844a-41d3-acd2-5b59b0742d27"}
Status =[ : 404
Error : Request failed with status code 404

Authentification Bearer

Si le service qu'on est sur le point de contacter nécessite un jeton, on peut utiliser un intercepteur qui va rajouter systématiquement le jeton. Ainsi, plus besoin de le préciser à chaque appel.

const requestHandler = (config) => {
    if (!config.headers['Authorization']) {
        config.headers['Authorization'] = `Bearer MY_TOKEN`;
    }
    return config;
};

// Pas obligé de définir les deux fonctions si on ne veut gérer qu'un cas
instance.interceptors.request.use(requestHandler, null);

makeRequest('/bearer', 'get');

intercept.js

$ node intercept.js
Response : {"authenticated":true,"token":"MY_TOKEN"}

Retenter un appel

Comme les intercepteurs récupèrent non seulement la donnée transférée mais aussi la configuration, on peut utiliser ce contexte afin de lancer de nouvelles requêtes.

On peut, par exemple, retenter le même appel en augmentant le timeout.

const responseHandler = (response) => {
    console.log(`Status =] : ${response.status}`);
    return response;
};

const responseErrorHandler = (error) => {
    const { config } = error;
    config.retryCount = config.retryCount || 0;
    config.timeout = config.timeout || 1000; // Timeout initial (en millisecondes)

    if (config.retryCount < 3) { // Nombre maximum de retentatives (3 dans cet exemple)
        config.retryCount += 1;
        config.timeout *= 2; // Augmentation du timeout à chaque tentative
        console.log(`Je reteste ${config.url} ${config.retryCount} fois - Nouveau timeout : ${config.timeout} ms`);

        return instance(config); // Retenter la requête avec la configuration modifiée
    }

    return Promise.reject(error);
};

instance.interceptors.response.use(responseHandler, responseErrorHandler);

makeRequest('/delay/3', 'get');

intercept.js

$ node intercept.js
Je reteste /delay/3 1 fois - Nouveau timeout : 2000 ms
Je reteste /delay/3 2 fois - Nouveau timeout : 4000 ms
Status =] : 200
Response : {"args":{},"data":"","files":{},"form":{},"headers":{"Accept":"application/json, text/plain, */*","Accept-Encoding":"gzip, compress, deflate, br","Connection":"close","Host":"localhost:2137","User-Agent":"axios/1.4.0"},"origin":"172.17.0.1","url":"http://localhost:2137/delay/3"}

Conclusion

On vient de coder des intercepteurs à notre niveau mais, comme il existe un module npm pour tout, ce qu'on a vu ensemble existe dans des modules populaires. Par exemple, axios-retry permet de retenter les connexions. Peut-être que c'est une bibliothèque que vous utilisiez sans savoir qu'elle se base sur les intercepteurs.

Maintenant que vous avez une meilleure compréhension des intercepteurs Axios, pourquoi ne pas passer à la prochaine étape ? Apprendre à déployer efficacement vos applications est essentiel, et Docker est un outil incontournable dans ce domaine.

Déployez comme un pro : le guide ultime pour Dockeriser votre application Node.js !
Découvrez Docker en toute sérénité ! Grâce à ce guide étape par étape, transformez votre application Node.js en un conteneur Docker.

Dernier