Aller au contenu

Le serveur de l'app

Certaines choses ne doivent pas se passer dans le navigateur de tes visiteurs : appeler une API avec une clé secrète, envoyer un e-mail, recevoir un webhook. Pour cela, ton app peut avoir son propre serveur, avec des routes sous /api. Il n’existe que si ton app en a besoin, et Highwind s’occupe de toute sa configuration.

Appeler un service avec une clé

IA (OpenAI, Mistral…), paiements, envoi d’e-mails, cartes : la clé reste sur le serveur et n’arrive jamais dans le navigateur.

Envoyer des messages

Formulaire de contact par e-mail, notification dans Slack, inscription ajoutée à une feuille Google Sheets.

Recevoir des webhooks

Un service externe (paiement, formulaire, automatisation) prévient ton app qu’un événement a eu lieu.

Contourner une API fermée au navigateur

Certaines API refusent les appels venant directement d’une page web : le serveur les appelle à sa place.

Si ton app a seulement besoin de garder des données pour le visiteur, ou d’une base de données avec des comptes utilisateurs, le serveur n’est pas forcément nécessaire : voir Où vont les données.

Une app n’a pas de serveur au départ. Quand une fonction en a besoin, l’agent l’ajoute lui-même (étape « Ajoute un serveur à l’app » dans le fil), ou en branchant un connecteur qui en a besoin.

  1. Highwind crée le fichier worker/index.ts à partir de son modèle et branche toute la configuration. L’agent n’écrit jamais cette configuration lui-même.

  2. L’agent ajoute les routes dont ton app a besoin dans worker/index.ts, par exemple POST /api/contact.

  3. Le front de ton app appelle ces routes avec des adresses relatives (fetch("/api/contact")), qui fonctionnent dans l’aperçu comme une fois publiée.

  4. Si une route a besoin d’une clé, l’agent te la demande avec une carte dans le chat : voir Les secrets.

Tu peux aussi le demander directement :

Ajoute un formulaire de contact qui m'envoie chaque message par e-mail à
contact@monatelier.fr, avec validation des champs.
Ajoute une route qui génère une description de produit avec OpenAI à partir
du nom et des caractéristiques saisis.
  • Il reçoit toutes les requêtes /api/*. Tout le reste (les pages, les images, les scripts) est le front de ton app.
  • Il tourne sur le moteur Cloudflare Workers, dans l’aperçu comme une fois publié : ce qui marche dans l’aperçu marche en ligne. Ce moteur fournit les API web standard (fetch, Request, Response, crypto.subtle), mais pas de système de fichiers, pas de processus qui tourne en continu et pas d’Express.
  • Une route inconnue répond une erreur 404 en JSON. Une erreur non rattrapée est écrite dans les logs et le visiteur reçoit une erreur 500 générique, sans détail technique.
  • Une app sans serveur ne change pas : elle reste un site statique. Si le fichier worker/index.ts est supprimé, l’app redevient statique.

Le serveur déclare ses routes dans une table routes (« MÉTHODE /api/chemin »), lit ses secrets dans env et répond avec l’utilitaire json() :

worker/index.ts (extrait)
export interface Env {
RESEND_API_KEY: string;
}
const routes: Record<string, Handler> = {
"GET /api/health": () => json({ ok: true }),
"POST /api/contact": async (request, env) => {
const { email, message } = await request.json();
if (!email || !message) return json({ error: "Champs obligatoires manquants" }, 400);
if (!env.RESEND_API_KEY) return json({ error: "Clé Resend pas encore ajoutée" }, 503);
// … envoi de l'e-mail avec env.RESEND_API_KEY
return json({ ok: true });
},
};

Quand une route ne fait pas ce que tu attends, les logs montrent ce qui s’est passé : les console.log du serveur et les erreurs, avec le fichier et la ligne.

  1. Dans la barre de l’aperçu, clique sur l’icône Logs du serveur. Le panneau s’ouvre en bas de l’aperçu.

  2. Choisis l’onglet :

    • Aperçu : le serveur de ton aperçu (les console.log et les erreurs des routes /api, et les messages de Vite), rafraîchi en continu. Les lignes d’erreur sont en rouge.
    • En ligne : le serveur de ton app publiée, sur les 24 dernières heures, avec quelques secondes de retard. Chaque appel à /api y apparaît avec son statut et sa durée, avec les console.log et les erreurs. Ni les en-têtes ni l’adresse IP des visiteurs ne sont affichés.
  3. Si tu ne comprends pas l’erreur, demande à l’agent de corriger : il lit lui-même ces logs (outil read_logs), dans l’aperçu ou en ligne.

Le formulaire de contact répond une erreur dans l'app publiée alors qu'il marche
dans l'aperçu. Regarde les logs en ligne et corrige.

N’importe qui peut appeler les routes /api de ton app, pas seulement ses pages. L’agent applique donc ces règles à chaque route :

  • Valider chaque donnée reçue et répondre une erreur claire avec le bon code (400 pour une saisie invalide, par exemple).
  • Ne jamais renvoyer un secret ni le détail technique d’une erreur au navigateur.
  • Limiter les routes qui envoient des messages ou dépensent de l’argent : destinataire fixé sur le serveur, champs obligatoires, utilisateur connecté quand l’app a une base de données.
  • Lire les secrets uniquement sur le serveur, jamais dans le code du front (src/).

Highwind ajoute ses propres garde-fous sur les apps publiées :

Garde-fou Valeur
Requêtes /api par visiteur et par app 120 par minute, puis erreur 429 (« réessaie dans une minute »)
Requêtes /api par app, tous visiteurs confondus 3 000 par minute
Temps de calcul par requête 1 seconde de CPU (l’attente des API externes ne compte pas)
Appels sortants par requête 200

Les pages et les fichiers statiques de ton app ne sont pas concernés par ces limites.