ITSkillsCenter
Développement Web

Guide pratique : Les requêtes AJAX avec JavaScript

5 min de lecture

AJAX en 2026 : fetch() a remplacé XMLHttpRequest

AJAX (Asynchronous JavaScript and XML) permet à votre page web de communiquer avec un serveur sans rechargement. Aujourd’hui, on n’utilise plus l’ancien XMLHttpRequest — l’API fetch() est plus simple, plus lisible et supportée par tous les navigateurs modernes. Ce guide vous montre comment l’utiliser concrètement avec des exemples que vous pouvez tester immédiatement.

Votre première requête GET

// Récupérer des données depuis une API
fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    if (!response.ok) {
      throw new Error('Erreur HTTP : ' + response.status);
    }
    return response.json();
  })
  .then(data => {
    console.log('Titre :', data.title);
    console.log('Contenu :', data.body);
  })
  .catch(error => {
    console.error('Erreur :', error.message);
  });

Ce qui se passe :

  1. fetch() envoie une requête GET à l’URL et retourne une Promesse
  2. response.ok vérifie que le statut HTTP est entre 200 et 299
  3. response.json() parse le corps de la réponse en objet JavaScript
  4. .catch() attrape les erreurs réseau (pas les erreurs 404/500 !)

La même requête avec async/await

async function recupererArticle(id) {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/' + id);
    
    if (!response.ok) {
      throw new Error('Article non trouvé (HTTP ' + response.status + ')');
    }
    
    const article = await response.json();
    return article;
  } catch (error) {
    console.error('Erreur :', error.message);
    return null;
  }
}

// Utilisation
const article = await recupererArticle(1);
console.log(article.title);

async/await rend le code asynchrone aussi lisible que du code synchrone. Le try/catch gère les erreurs de manière claire.

Envoyer des données avec POST

async function creerArticle(titre, contenu) {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      title: titre,
      body: contenu,
      userId: 1
    })
  });
  
  const nouvelArticle = await response.json();
  console.log('Article créé avec ID :', nouvelArticle.id);
  return nouvelArticle;
}

creerArticle('Mon titre', 'Mon contenu ici');

Points clés du POST :

  • method: 'POST' — sans ça, fetch envoie un GET par défaut
  • Content-Type: application/json — dit au serveur que le body est du JSON
  • JSON.stringify() — convertit l’objet JavaScript en chaîne JSON

PUT, PATCH et DELETE

// PUT : remplacer entièrement une ressource
await fetch('/api/articles/42', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Nouveau titre', body: 'Nouveau contenu' })
});

// PATCH : modifier partiellement
await fetch('/api/articles/42', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Titre corrigé' })
});

// DELETE : supprimer
await fetch('/api/articles/42', { method: 'DELETE' });

Envoyer un formulaire avec FormData

const form = document.getElementById('monFormulaire');

form.addEventListener('submit', async (e) => {
  e.preventDefault();
  
  const formData = new FormData(form);
  
  // Pour uploader un fichier
  const response = await fetch('/api/upload', {
    method: 'POST',
    body: formData  // PAS de Content-Type ici — le navigateur le définit automatiquement
  });
  
  const result = await response.json();
  console.log('Fichier uploadé :', result.url);
});

Important : quand vous envoyez un FormData, ne définissez PAS le header Content-Type. Le navigateur le fait automatiquement avec le bon boundary pour le multipart/form-data.

Gestion avancée des erreurs

async function fetchAvecGestion(url, options = {}) {
  try {
    const response = await fetch(url, {
      ...options,
      signal: AbortSignal.timeout(10000) // Timeout de 10 secondes
    });
    
    if (response.status === 401) {
      // Rediriger vers la page de connexion
      window.location.href = '/login';
      return;
    }
    
    if (response.status === 404) {
      console.warn('Ressource non trouvée :', url);
      return null;
    }
    
    if (!response.ok) {
      const errorData = await response.json().catch(() => ({}));
      throw new Error(errorData.message || 'Erreur serveur ' + response.status);
    }
    
    return await response.json();
  } catch (error) {
    if (error.name === 'TimeoutError') {
      console.error('La requête a pris trop de temps');
    } else if (error.name === 'TypeError') {
      console.error('Problème réseau — vérifiez votre connexion');
    } else {
      console.error('Erreur :', error.message);
    }
    return null;
  }
}

Exemple complet : recherche en temps réel

const searchInput = document.getElementById('search');
const resultsList = document.getElementById('results');
let debounceTimer;

searchInput.addEventListener('input', (e) => {
  clearTimeout(debounceTimer);
  
  debounceTimer = setTimeout(async () => {
    const query = e.target.value.trim();
    if (query.length < 2) {
      resultsList.innerHTML = '';
      return;
    }
    
    const data = await fetchAvecGestion(
      '/api/search?q=' + encodeURIComponent(query)
    );
    
    if (data) {
      resultsList.innerHTML = data.results
        .map(r => '<li>' + r.title + '</li>')
        .join('');
    }
  }, 300); // Attendre 300ms après la dernière frappe
});

Le debounce évite d’envoyer une requête à chaque caractère tapé. On attend que l’utilisateur arrête de taper pendant 300ms avant d’envoyer la requête. Essayez sans debounce, puis avec, pour voir la différence dans l’onglet Network de DevTools.

Exercice pratique

  1. Créez une page qui récupère et affiche une liste de 10 utilisateurs depuis https://jsonplaceholder.typicode.com/users
  2. Ajoutez un formulaire pour créer un nouveau post (POST vers /posts)
  3. Affichez un spinner de chargement pendant la requête
  4. Gérez les erreurs avec un message visible à l’utilisateur
  5. Bonus : ajoutez une recherche en temps réel avec debounce
#ajax #asynchrone #javascript
Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 350.000 FCFA
Parlons de Votre Projet
Publicité

Articles Similaires