Skip to content

Form Handler

Form Handler

Documentation technique

Type de ressource : Cloudflare Worker (Microservice FaaS)
Fichier source : services/form-handler/src/index.ts
Statut : Actif

1. Vue d’ensemble

1.1. Description

Worker Cloudflare pour la validation et la mise en queue des soumissions de formulaire. Valide les données entrantes via Zod, crée un objet de soumission avec métadonnées, et l’envoie dans la Queue Cloudflare pour un traitement asynchrone.

1.2. Objectif

  • Valider les soumissions de formulaire côté serveur
  • Découpler la validation du traitement asynchrone
  • Utiliser une Queue Cloudflare pour le traitement en arrière-plan
  • Fournir une réponse immédiate au frontend

1.3. Caractéristiques

Propriété Valeur
Type Microservice métier
Trigger HTTP fetch
Route publique /api/submit, /health
Environnements Development, Production
Consommateurs Astro (frontend), Submission-processor (Queue consumer)

2. Architecture et flux

[Entrée : Astro / Navigateur]
│ • POST /api/submit
▼
[Form Handler Worker]
│ • Validation Zod (name, email, message)
│ • Création de l'objet de soumission
│ • Envoi dans la Queue
▼
[Queue Cloudflare (submissions-queue)]
│
▼
[Submission-processor Worker]
│ • Création du document Sanity
▼
[Sanity CMS]

2.2. Positionnement dans la chaîne Edge

[Client]
│
▼
[Astro Frontend]
│ • POST /api/submit
▼
[Form Handler Worker]
│
▼
[Queue Cloudflare]
│
▼
[Submission-processor Worker]
│
▼
[Sanity CMS]

2.3. Composants impliqués

Composant Rôle Type
Zod Validation des entrées Bibliothèque
SUBMISSIONS_QUEUE Queue asynchrone Cloudflare Binding
Submission-processor Consommateur de la Queue Cloudflare Worker
Sanity API Stockage des soumissions Service tiers

3. Configuration

3.1. Variables d’environnement

Variable Description Obligatoire Valeur par défaut
ENVIRONMENT Environnement (dev/production) ✅ dev

3.2. Bindings Cloudflare

Binding Type Nom Description
SUBMISSIONS_QUEUE Queue SUBMISSIONS_QUEUE Queue pour les soumissions

3.3. Configuration Wrangler (wrangler.toml)

services/form-handler/wrangler.toml
name = "amn-form-handler"
main = "src/index.ts"
compatibility_date = "2025-07-18"
compatibility_flags = ["nodejs_compat"]
[vars]
ENVIRONMENT = "dev"
[[queues.producers]]
queue = "submissions-queue-dev"
binding = "SUBMISSIONS_QUEUE"
[env.dev]
name = "amn-form-handler-dev"
vars = { ENVIRONMENT = "dev" }
[[env.dev.queues.producers]]
queue = "submissions-queue-dev"
binding = "SUBMISSIONS_QUEUE"
[env.production]
name = "amn-form-handler-prod"
vars = { ENVIRONMENT = "production" }
[[env.production.queues.producers]]
queue = "submissions-queue-prod"
binding = "SUBMISSIONS_QUEUE"

3.4. Injection des secrets

Aucun secret n’est injecté dans ce service.

4. Implémentation

4.1. Code de production (src/index.ts)1/2

4.1. Code de production (src/index.ts)2/2

import { z } from 'zod'
// Schema validation for form submission
const SubmissionSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
message: z.string().min(10).max(2000),
})
export interface Env {
SUBMISSIONS_QUEUE: Queue;
ENVIRONMENT: string;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Handle CORS preflight
if (request.method === 'OPTIONS') {
return handleCors();
}
// Handle POST requests for form submission
if (request.method === 'POST' && url.pathname === '/api/submit') {
return handleSubmit(request, env);
}
// Health check endpoint
if (request.method === 'GET' && url.pathname === '/health') {
return new Response(JSON.stringify({
status: 'healthy',
environment: env.ENVIRONMENT,
timestamp: new Date().toISOString()
}), {
headers: { 'Content-Type': 'application/json' },
});
}
return new Response('Not Found', { status: 404 });
},
};
async function handleSubmit(request: Request, env: Env): Promise<Response> {
try {
const body = await request.json();
// Validate input
const validatedData = SubmissionSchema.parse(body);
// Create submission object with metadata
const submission = {
...validatedData,
submittedAt: new Date().toISOString(),
id: crypto.randomUUID(),
environment: env.ENVIRONMENT,
};
// Send to queue for async processing
await env.SUBMISSIONS_QUEUE.send(submission);
// Return immediate success response
return new Response(JSON.stringify({
success: true,
message: 'Form submitted successfully',
id: submission.id,
}), {
headers: {
'Content-Type': 'application/json',
...corsHeaders(),
},
});
} catch (error) {
if (error instanceof z.ZodError) {
return new Response(JSON.stringify({
success: false,
error: 'Validation failed',
details: error.issues,
}), {
status: 400,
headers: {
'Content-Type': 'application/json',
...corsHeaders(),
},
});
}
console.error('Submission error:', error);
return new Response(JSON.stringify({
success: false,
error: 'Internal server error',
}), {
status: 500,
headers: {
'Content-Type': 'application/json',
...corsHeaders(),
},
});
}
}
function corsHeaders(): Record<string, string> {
return {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
}
function handleCors(): Response {
return new Response(null, {
status: 204,
headers: corsHeaders(),
});
}

4.2. Interfaces et types

// Schema Zod
const SubmissionSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
message: z.string().min(10).max(2000),
});
// Interface des bindings
export interface Env {
SUBMISSIONS_QUEUE: Queue;
ENVIRONMENT: string;
}
// Type de soumission
type Submission = {
name: string;
email: string;
message: string;
submittedAt: string;
id: string;
environment: string;
};

5. Sécurité

5.1. Mécanismes de sécurité

Mécanisme Implémentation Rationale
Validation Zod Validation stricte des entrées Prévention des injections
CORS Headers CORS permissifs Permettre les requêtes cross-origin
Aucun secret Pas de secret injecté Pas de données sensibles dans ce service

5.2. Validation des entrées

  • ✅ Validation Zod du nom (min 2, max 100)
  • ✅ Validation Zod de l’email (format email)
  • ✅ Validation Zod du message (min 10, max 2000)

5.3. Gestion des secrets

Non applicable - aucun secret n’est utilisé dans ce service.

6. Résilience et gestion des erreurs

6.1. Stratégie de retry

Scénario Stratégie Rationale
Queue failure Pas de retry Simple retry dans le Queue consumer

6.2. Safety Locks

Non implémenté - pas de lock configuré.

6.3. Gestion des timeouts

  • ✅ Timeout global : Dépend de Cloudflare (30s Free / 50s Paid)
  • ✅ Timeout par service tiers : Dépend de Cloudflare

7. Performance et limites

7.1. Limites Cloudflare Workers

Limite Valeur Stratégie d’optimisation
Mémoire RAM 128 MB Pas de traitement lourd en mémoire
CPU time 30s (Free) / 50s (Paid) Validation rapide
Nombre de sous-requêtes 50 Pas de sous-requêtes
Taille requête/réponse 100 MB Payload de formulaire limité

7.2. Optimisations appliquées

  • ✅ Validation rapide (Zod)
  • ✅ Mise en queue asynchrone (pas d’attente pour le traitement)
  • ✅ Pas de chargement en mémoire

8. Monitoring et observabilité

8.1. Logs structurés

Non implémenté - logs console.error basiques.

8.2. Métriques clés

Non implémenté - aucune métrique ou alerte n’est configurée.

8.3. Commandes de debug

Terminal window
# Logs en temps réel
wrangler tail form-handler
# Vérification des bindings
wrangler deployments list

9. Déploiement

9.1. Pipeline de déploiement

Terminal window
# Build
npm run build --workspace=services/form-handler
# Déploiement staging
wrangler deploy --env staging
# Déploiement production
wrangler deploy --env production

9.2. Rollback

Terminal window
# Liste des déploiements
wrangler deployments list
# Rollback vers une version précédente
wrangler deployments rollback --deployment-id=[id]

9.3. Tests manuels

Terminal window
# Test HTTP
curl -X POST http://localhost:8789/api/submit \
-H "Content-Type: application/json" \
-d '{"name":"Test","email":"test@example.com","message":"Test message"}'
# Test health check
curl http://localhost:8789/health

10. Débogage et troubleshooting

10.1. Problèmes courants

Symptôme Cause probable Solution
Validation échoue Données invalides Vérifier les règles Zod
Queue non disponible Binding mal configuré Vérifier wrangler.toml
CORS error Headers CORS manquants Vérifier la configuration CORS

10.2. Erreurs fréquentes

Code HTTP / Erreur Signification Action
400 Validation échouée Corriger les données du formulaire
500 Erreur serveur Vérifier les logs du Worker

11. Bonnes pratiques

11.1. Architecture

  • ✅ Découpler la validation du traitement asynchrone
  • ✅ Utiliser les bindings Cloudflare plutôt que des appels HTTP internes
  • ✅ Responsabilité unique (validation et mise en queue)

11.2. Code

  • ✅ Typer strictement les bindings et les réponses
  • ✅ Valider toutes les entrées (Zod)
  • ✅ Gérer explicitement les erreurs (try/catch)
  • ✅ Logger les erreurs

11.3. Sécurité

  • ✅ Valider toutes les entrées côté serveur
  • ✅ Utiliser Zod pour la validation

11.4. Performance

  • ✅ Validation rapide
  • ✅ Mise en queue asynchrone

12. Évolutions et roadmap

12.1. Améliorations planifiées

  • Configuration de Logpush pour les logs
  • Ajout de métriques et alertes
  • Ajout de rate limiting
  • Amélioration de la validation (CAPTCHA)

12.2. Limitations connues

  • ❌ CORS permissif (*) - à restreindre pour la production
  • ❌ Pas de rate limiting
  • ❌ Pas de logs structurés
  • ❌ Pas de monitoring configuré

13. Ressources liées1/2

  • Documentation Cloudflare Workers : Getting Started
  • Documentation Cloudflare Queues : Queues
  • Documentation Zod : Zod
  • Workers associés :
    • submission-processor

13. Ressources liées2/2

  • Fichiers concernés :
    • services/form-handler/src/index.ts
    • services/form-handler/wrangler.toml
    • services/form-handler/package.json

14. Historique des modifications

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

Contents