Skip to content

API Submit

API Submit

Documentation technique

Type de ressource : Route Astro (Endpoint API)
Fichier source : src/pages/api/submit.ts
Statut : Actif

1. Vue d’ensemble

1.1. Description

Endpoint API pour la soumission du formulaire de contact. Valide les données, envoie vers le form-handler Worker (local ou production via Cloudflare binding), et retourne le résultat. Partie intégrante du flux L1+L2+L3.

1.2. Objectif

  • Recevoir les soumissions du formulaire de contact
  • Valider les données
  • Envoyer vers le backend L3 (Cloudflare Workers)
  • Retourner le résultat au frontend

1.3. Caractéristiques

Propriété Valeur
URL publique /api/submit
Mode de rendu SSR
Type Endpoint API (JSON)
Méthode HTTP POST
Authentification requise Non
Cache No-store

2. Architecture et flux

[Formulaire soumis]
│ • POST /api/submit
▼
[Endpoint /api/submit]
│ • Détection de l'environnement (local vs production)
▼
[Local]
│ • Fetch vers http://localhost:8789/test-direct
▼
[Form-handler Worker (local)]
│ • Validation Zod
│ • Création directe dans Sanity
▼
[Sanity CMS]
[Production]
│ • Utilisation du service binding FORM_HANDLER
▼
[Form-handler Worker (Cloudflare)]
│ • Validation Zod
│ • Mise en queue dans submissions-queue
▼
[Queue Cloudflare]
│
▼
[Submission-processor Worker]
│ • Création du document Sanity
▼
[Sanity CMS]

2.2. Composants impliqués

Composant Rôle Couche
api/submit.ts Définition de l’endpoint L2 (Astro)
Form-handler Worker Validation et mise en queue L3 (Cloudflare)
Submission-processor Worker Création document Sanity L3 (Cloudflare)
Queue Cloudflare Queue asynchrone L3 (Cloudflare)
Sanity CMS Stockage des soumissions L1 (Sanity)

3. Implémentation

3.1. Code de l’endpoint1/2

3.1. Code de l’endpoint2/2

import type { APIRoute } from 'astro';
import { env } from 'cloudflare:workers';
export const prerender = false;
export const POST: APIRoute = async (context) => {
const { request } = context;
try {
const data = await request.json();
const url = new URL(request.url);
const isLocal = url.hostname === 'localhost' ||
url.hostname === '127.0.0.1' ||
url.port === '4321';
let response: Response;
if (isLocal) {
// En local, on continue d'appeler le port local en HTTP classique
response = await fetch('http://localhost:8789/test-direct', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
} else {
// En production : Utilisation de l'import natif validé par Astro v6
const formHandler = (env as any).FORM_HANDLER;
if (!formHandler) {
const keys = Object.keys(env || {});
throw new Error(`Le Service Binding 'FORM_HANDLER' est introuvable. Éléments dispo dans env: [${keys.join(', ')}]`);
}
// Appel sécurisé via le binding avec l'URL interne
response = await formHandler.fetch('http://internal/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
}
const responseText = await response.text();
try {
const result = JSON.parse(responseText);
return new Response(JSON.stringify(result), {
status: response.status,
headers: { 'Content-Type': 'application/json' },
});
} catch {
return new Response(JSON.stringify({
success: false,
error: 'Invalid JSON response from downstream worker',
details: responseText
}), {
status: response.status,
headers: { 'Content-Type': 'application/json' },
});
}
} catch (error: any) {
console.error('Erreur réelle détectée lors de la soumission :', error.stack || error.message || error);
return new Response(JSON.stringify({
success: false,
error: 'Failed to process submission',
debugMessage: error.message,
debugStack: error.stack
}), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
};

4. Données et requêtes GROQ

Aucune requête GROQ n’est utilisée dans cet endpoint (la logique est déléguée aux Workers).

5. Paramètres et validation

5.1. Body JSON

Champ Type Obligatoire Validation
name string ✅ Min 2, Max 100 (validé par Worker)
email string ✅ Format email (validé par Worker)
message string ✅ Min 10, Max 2000 (validé par Worker)

5.2. Gestion des erreurs

Code HTTP Condition Réponse
200 Succès JSON avec success: true
400 Validation échouée JSON avec error: validation
500 Erreur serveur JSON avec error + debug info

6. Stratégie de cache

6.1. En-têtes de cache

Mode Cache-Control Rationale
API (POST) Non configuré À configurer (no-store recommandé)

6.2. Implémentation dans l’endpoint

Non implémenté - pas de headers de cache explicites.

7. SEO et métadonnées

Non applicable (endpoint API).

8. Composants UI utilisés

Aucun composant UI n’est utilisé (endpoint API).

9. Sécurité

9.1. Accès et authentification

Condition Comportement
Accès public Endpoint accessible sans authentification

9.2. Validation des entrées

  • ✅ Validation côté serveur via Zod (Worker)
  • ✅ Validation côté client (HTML5)

9.3. En-têtes de sécurité

Non implémenté dans cet endpoint (à configurer via Middleware Cloudflare).

10. Débogage et troubleshooting

10.1. Problèmes courants

Symptôme Cause probable Solution
Service binding introuvable FORM_HANDLER non configuré Vérifier apps/web/wrangler.toml
Erreur 500 Worker inaccessible Vérifier que le form-handler Worker est démarré
JSON invalide Worker retourne une réponse non-JSON Vérifier les logs du Worker

10.2. Logs et monitoring

Terminal window
# Logs de développement
npm run dev
# Logs du form-handler Worker
wrangler tail form-handler
# Logs du submission-processor Worker
wrangler tail submission-processor

10.3. Tests manuels

Terminal window
# Test de l'endpoint en local
curl -X POST http://localhost:4321/api/submit \
-H "Content-Type: application/json" \
-d '{"name":"Test","email":"test@example.com","message":"Test message"}'

11. Bonnes pratiques

11.1. Architecture

  • ✅ Détection automatique de l’environnement (local vs production)
  • ✅ Utilisation des Cloudflare bindings en production
  • ✅ Fallback vers HTTP local en développement
  • ✅ Logging des erreurs avec stack trace

11.2. Performance

  • ✅ Asynchrone (pas de blocage)
  • ✅ Queue pour le traitement en arrière-plan

11.3. Maintenance

  • ✅ Vérifier la configuration des bindings Cloudflare
  • ✅ Surveiller les logs des Workers

12. Évolutions et roadmap

12.1. Améliorations planifiées

  • Configuration des headers de cache (no-store)
  • Ajout de rate limiting
  • Ajout de CAPTCHA

12.2. Limitations connues

  • ❌ Headers de cache non configurés
  • ❌ Pas de rate limiting
  • ❌ Pas de CAPTCHA
  • ⚠️ Utilisation de as any pour le binding FORM_HANDLER

13. Ressources liées

  • Documentation Astro : Endpoints
  • Documentation Cloudflare : Service Bindings
  • Fichiers concernés :
    • src/pages/api/submit.ts
    • services/form-handler/src/index.ts
    • services/submission-processor/src/index.ts
    • apps/web/wrangler.toml

14. Historique des modifications

Date Version Description Auteur
2026-09-15 1.0 Création initiale Devin
Switch to normal mode

Contents