Leçon 6 / 20

Publier une tâche depuis l’API

25 min Node.js — production, files d’attente et sécurité Gratuit

Objectif : Enregistrer une commande et demander sa facturation sans attendre la génération du document.

Lorsqu’une requête génère elle-même une facture, le client attend la fin d’un travail qui peut prendre du temps. Vous allez modifier ce parcours pour que l’API enregistre d’abord la commande, puis transmette une demande de facturation à la file.

La réponse HTTP confirme la prise en charge de la demande, pas la création du document. Le traitement effectif sera confié au worker dans une leçon ultérieure ; ici, vous définissez seulement la frontière entre l’API et le producteur de tâches.

Le parcours de la requête

La route reçoit les données nécessaires à la commande et appelle le dépôt pour la persister. Seulement après la confirmation de l’enregistrement, elle construit le message avec creerTacheFacture, défini dans la leçon précédente, et le remet au producteur injecté.

Le producteur est l’adaptateur responsable de l’envoi vers la file choisie. La route ne dépend donc pas directement d’une bibliothèque de file ou d’un serveur particulier : elle attend une fonction publier qui reçoit un message de tâche valide.

Définir la route et ses dépendances

Dans src/routes/commandes.js, exportez une fabrique de route plutôt qu’un routeur lié à des services globaux. Le contrat du dépôt est volontairement explicite : creer enregistre les données reçues et renvoie la commande avec son identifiant ; le producteur confirme la publication en résolvant sa promesse.

src/routes/commandes.jsTexte
import { Router } from 'express';
import { creerTacheFacture } from '../queues/factures.js';

export function creerRouteurCommandes({ commandes, producteurFactures, journal }) {
  if (!commandes || typeof commandes.creer !== 'function') {
    throw new TypeError('Le dépôt des commandes est obligatoire.');
  }
  if (!producteurFactures || typeof producteurFactures.publier !== 'function') {
    throw new TypeError('Le producteur de factures est obligatoire.');
  }

  const routeur = Router();

  routeur.post('/', async (requete, reponse, suivant) => {
    try {
      const commande = await commandes.creer(requete.body);
      const tache = creerTacheFacture(commande.id);
      await producteurFactures.publier(tache);

      return reponse.status(202).json({
        commandeId: commande.id,
        statut: 'facturation_demandee'
      });
    } catch (erreur) {
      if (journal) {
        journal.error({
          evenement: 'publication_facture_echouee',
          correlationId: requete.correlationId,
          message: erreur.message
        });
      }
      return suivant(erreur);
    }
  });

  return routeur;
}

L’ordre des deux appels est essentiel : une publication ne doit pas précéder la persistance, car le worker pourrait recevoir une tâche qui désigne une commande inexistante. La réponse 202 Accepted indique que la demande a été acceptée pour traitement différé ; elle ne signifie pas que la facture est déjà disponible.

Injecter la route dans l’application

Dans src/app.js, montez le routeur sous /commandes en lui passant les dépendances déjà créées par votre composition d’application. Les noms ci-dessous illustrent le contrat à raccorder : utilisez les instances de dépôt, de producteur et de journal de votre application, sans créer de dépendance globale dans le fichier de routes.

Montage dans src/app.jsTexte
import express from 'express';
import { creerRouteurCommandes } from './routes/commandes.js';

export function creerApplication({ commandes, producteurFactures, journal }) {
  const application = express();

  application.use(express.json());
  application.use('/commandes', creerRouteurCommandes({
    commandes,
    producteurFactures,
    journal
  }));

  application.use((erreur, requete, reponse, suivant) => {
    if (reponse.headersSent) {
      return suivant(erreur);
    }
    return reponse.status(500).json({ erreur: 'Erreur interne du service.' });
  });

  return application;
}

Une requête POST /commandes avec un corps JSON valide passe par le dépôt puis par le producteur. Lorsque les deux opérations réussissent, la réponse contient l’identifiant attribué par le dépôt et le statut de prise en charge. Dans cette version, le contrat du dépôt doit refuser ou traiter correctement les données invalides ; les règles détaillées de validation ne sont pas l’objet de cette étape.

À retenir

  • Persistez la commande avant de publier la tâche qui la référence.
  • Injectez le producteur dans la route et laissez-lui la responsabilité de communiquer avec la file.
  • Répondez avec 202 après confirmation de publication : la facture n’est pas encore générée.
  • En cas d’échec de publication, ne prétendez pas que la demande a été prise en charge.

Dans la prochaine leçon, vous séparerez le worker du serveur web et consommerez les tâches publiées par cette route.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.