Cesser d'utiliser XMLHttpRequest et passer à fetch

L’API XHR la plus populaire est XMLHttpRequest qui n’a pas vraiment été faite pour ce pour quoi nous l’utilisons. C’est pourquoi l’API fetch a été créée, l’API fetch est en quelque sorte un remplacement moderne pour XMLHttpRequest. Jetons un coup d’oeil à cette méthode window.fetch.

Compatibilité des navigateurs

Une chose importante lors du développement d’une application web est la compatibilité du navigateur avec les technologies utilisées. Comme XMLHttpRequest est plus ancien, il a logiquement une meilleure compatibilité avec les navigateurs plus anciens par rapport à fetch, cependant, il y a des polyfill’s bien faits qui rendent cette API moderne compatible avec les navigateurs plus anciens tels que IE, etc…

(c.f Compatibilité XMLHttpRequest, Compatibilité Fetch)

Utilisation de base de XMLHttpRequest

XHR est un peu trop compliqué à mon avis et je ne comprends toujours pas pourquoi XML est en majuscules alors que Http est en camel-case, cela n’a aucun sens. Quoi qu’il en soit, voici un usage courant de l’API XHR

if (window.XMLHttpRequest) { // Mozilla, Safari, etc...
    request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
    try {
        request = new ActiveXObject('Msxml2.XMLHTTP');
    } 
    catch (e) {
        try {
            request = new ActiveXObject('Microsoft.XMLHTTP');
        } 
        catch (e) {}
    }
}

// Ouvre la demande et l'envoie
request.open('GET', 'https://exemple.com/api', true);
request.send(null);

Bien sûr, les frameworks JavaScript rendent l’API XHR plus agréable à utiliser, mais ce que vous voyez ci-dessus est un exemple “simple” de l’utilisation la plus basique de XHR. XHR est un vrai gâchis.

Utilisation de base de fetch

L’API fetch est fournie dans l’objet window globale, le premier argument étant l’URL (obligatoire) et le second les options (facultatif).

// fetch(url, options) | url: obligatoire - options: facultatif
fetch('https://exemple.com/api', {
    method: 'get'
}).then(function(response) {
    // Succès :)
}).catch(function(err) {
    // Erreur :(
});

Et comme vous pouvez le voir, fetch utilise les promesses Javascript pour gérer les résultats et les callbacks. Si vous n’êtes pas encore habitué aux promesses Javascript, habituez-vous - elles seront bientôt partout.

En-têtes de requête

La possibilité de définir des en-têtes de requête est importante dans la flexibilité de la requête, vous pouvez travailler avec les en-têtes de requête en exécutant new Headers()

// Créer une instance d'en-têtes vide
const headers = new Headers();

// Ajouter des en-têtes
headers.append('EnTeteCustom', 'MaSuperValeur');
headers.append('Content-Type', 'text/html');

// Vérifier si cet en-tête est présent
headers.has('Content-Type'); // vrai
headers.has('Some-Header'); // faux

// Obtenir la valeur d'un en-tête spécifique
headers.get('EnTeteCustom'); // MaSuperValeur

// Définir une nouvelle valeur pour un en-tête existant
headers.set('Content-Type', 'text/plain');

// Supprimer une en-tête
headers.delete('EnTeteCustom');

// Additionner les valeurs initiales
const headers = new Headers({
    'Content-Type': 'application/json',
    'User-Agent': 'MonSuperUserAgent'
});

Pour utiliser les en-têtes de Request, vous devez d’abord créer une nouvelle instance de Request

const request = new Request('https://exemple.com/api', {
    headers: new Headers({
        'Content-Type': 'application/json',
        'User-Agent': 'MonSuperUserAgent'
    })
});

fetch(request).then(function(response) {
    // traiter la réponse
}).catch(function(error) {
    // traiter l'erreur
});

Requête

Une instance de Request représente l’élément de requête d’un appel de la méthode fetch. En passant une Request à l’API fetch, vous pouvez faire des demandes avancées et personnalisées:

  • method - GET, HEAD, POST, PUT, DELETE
  • url - URL de la requête
  • headers - objet Headers associé
  • referrer - référant de la requête
  • mode - cors, no-cors, same-origin
  • credentials - les cookies doivent-ils accompagner la demande ? omit, same-origin
  • redirect - follow, error, manual
  • integrity - valeur d’intégrité des sous-ressources
  • cache - mode du cache (default, reload, no-cache)

Voici un exemple d’utilisation de Request

// Construire la requête
const request = new Request('https://exemple.com/anything', {
    method: 'HEAD', 
    mode: 'no-cors', 
    redirect: 'follow',
    headers: new Headers({
        'Content-Type': 'text/html'
    })
});

// Et maintenant, utilisez la requête
fetch(request).then(function() {
    // handle response 
});

Seul le premier paramètre, l’URL, est requis. Chaque propriété ne peut être que lu dès que l’instance de la Request a été créée. Il est également important de noter que Request a une méthode de clonage qui est importante lors de l’utilisation de fetch dans l’API Service Worker - une Request est un flux et doit donc être clonée lors du passage à un autre appel de fetch.

fetch('https://exemple.com/anything', {
    method: 'HEAD', 
    mode: 'no-cors', 
    redirect: 'follow',
    headers: new Headers({
        'Content-Type': 'text/html'
    })
}).then(function() {
    // gérer la réponse 
});

Vous n’utiliserez probablement que des instances de Request au sein de Service Workers puisque les signatures Request et fetch peuvent être les mêmes.

Réponse

La méthode then de fetch est une instance de réponse mais vous pouvez également créer manuellement des objets de réponse vous-même – une autre situation que vous pouvez rencontrer lorsque vous utilisez des service workers. Avec une réponse, vous pouvez configurer:

  • type - basic, cors
  • url
  • useFinalURL - Booléen pour si url est l’URL finale.
  • status - code de statut (ex: 200, 404, etc.)
  • ok - Booléen pour une réponse réussie (statut dans la plage 200-299)
  • statusText - code de statut (ex: OK)
  • headers - Objet d’en-tête associé à la réponse.
// Fausse réponse pour les tests des service workers -- new Response(body, options)
const response = new Response('response body', {
    ok: false,
    status: 404,
    url: '/'
});

// Le then de fetch récupère alors une instance de réponse.
fetch('https://exemple.com/').then(function(response) {
    console.log('ok: ', response.ok); // faux
});

La Response fournit également les méthodes suivantes :

  • clone() Crée un clone d’un objet Response
  • error() Retourne un nouvel objet Response associé à une erreur réseau
  • redirect() Crée une nouvelle réponse avec une URL différente
  • arrayBuffer() Retourne une promesse qui se résout avec un ArrayBuffer
  • blob() Retourne une promesse qui se résout avec un Blob
  • formData() Retourne une promesse qui se résout avec un objet FormData
  • json() Retourne une promesse qui se résout avec un objet JSON
  • text() Retourne une promesse qui se résout avec une USVString (texte)

Manipulation du JSON

Disons que vous faites une requête pour JSON, les données de rappel résultantes ont une méthode json pour convertir les données brutes en objet JavaScript

fetch('https://exemple.com/api/list.json').then(function(response) { 
    // Convertir en JSON
    return response.json();
}).then(function(jsObj) {
    // jsObj est un objet javascript de la réponse json
    console.log(jsObj); 
});

La méthode json() est un simple raccourci vers JSON.parse(jsonString)

Manipulation des réponses Text/HTML

JSON n’est pas toujours le format de réponse désiré, alors voici comment vous pouvez travailler avec une réponse HTML ou textuelle

fetch('/404').then(function(response) {
    return response.text();
}).then(function(htmlresponse) { 
    // <!DOCTYPE ....
    console.log(htmlresponse); 
});

Vous pouvez obtenir le texte de réponse enchaînant la méthode then de la promesse avec la méthode text()

Manipulation des réponses Blob

Par exemple, charger une image via fetch est un peu différent

fetch('https://exemple.com/someimage.jpg').then(function(response) {
    return response.blob();
})
.then(function(imageBlob) {
    document.querySelector('img').src = URL.createObjectURL(imageBlob);
});

La méthode blob() du Body mixing prend un flux de réponse et le lit jusqu’à la fin.

Envoyer des données de formulaire

AJAX est beaucoup utilisé pour envoyer des données de formulaire, voici comment vous le feriez avec l’utilisation de fetch

fetch('https://exemple.com/submit', {
    method: 'post',
    body: new FormData(document.getElementById('myForm'))
});

Et si vous voulez poster des données JSON

fetch('https://exemple.com/submit', {
    method: 'post',
    body: JSON.stringify({
        some: document.querySelector('#some').value,
        json: document.querySelector('#json').value,
        data: document.querySelector('#data').value
    })
});

C’est aussi simple que ça !

Polyfill

Il y a beaucoup de Polyfill pour la méthode fetch, mais je vous suggère fortement de vous pencher sur celle de GitHub.