Esc
 Naviguer  Ouvrir Esc Fermer
Aller au contenu

10.4 — Patrons d'intégration

🎯 Objectif : assembler les briques d’une architecture composable cohérente, et savoir migrer quand le BaaS ne suffit plus.

À l'issue de cet axe, tu sauras :

  • Décrire le pattern JAMstack et ses limites
  • Construire un Backend-for-Frontend (BFF)
  • Utiliser les edge functions pour auth et personnalisation
  • Planifier une migration BaaS → backend custom sans downtime
  • Choisir entre tout-BaaS et stack composable

Confirmé 10 min prérequis : axes 8-9 lus

JAMstack = JavaScript + APIs + Markup. Au lieu d’un serveur Rails/Django qui rend chaque page, tu :

  1. Pré-génères le HTML statique (au build).
  2. Sers depuis un CDN.
  3. Appelles des APIs (les tiennes ou des BaaS) côté client pour les parties dynamiques.
flowchart LR
    User((User)) --> CDN[CDN<br/>HTML statique]
    User -->|fetch| Stripe[Stripe API]
    User -->|fetch| Sup[Supabase API]
    User -->|fetch| Sanity[Sanity CMS]
    Build[Build étape] --> CDN
    CMS[Sanity / Contentful] -->|webhook| Build
Architecture JAMstack typique
  • Performance brutale : CDN sert en ~10 ms partout.
  • Sécurité : pas de serveur applicatif côté toi (moins de surface d’attaque).
  • Coût quasi nul : un CDN coûte des centimes/mois.
  • Scalabilité infinie : tu peux servir des millions de pages sans serveur.
  • Logique métier complexe ne va pas dans le client.
  • Données fraîches demandent des fetch dynamiques (pas vraiment “static” alors).
  • Multi-tenant / personnalisation difficile à pré-générer.
Type de siteJAMstack ?
Blog, marketing, docs✅✅✅
E-commerce léger (< 1000 produits)✅✅
SaaS dashboard🟡 (mieux avec SSR via Next.js + Vercel)
App temps réel (chat)
Outils internes massifs

Le compromis moderne : SSR/ISR au lieu de JAMstack pur

Section intitulée « Le compromis moderne : SSR/ISR au lieu de JAMstack pur »

Avec Next.js + Vercel, tu peux mixer :

// Page complètement statique (SSG)
export default function HomePage() { ... }
// Page régénérée toutes les 60 s (ISR)
export const revalidate = 60;
export default async function ProductsPage() {
const products = await fetch('/api/products', { next: { revalidate: 60 } });
return ...;
}
// Page dynamique au runtime (SSR)
export const dynamic = 'force-dynamic';
export default async function DashboardPage() {
const user = await getCurrentUser();
return ...;
}

→ tu choisis par page entre statique, ISR, SSR, edge. C’est ce que fait Next.js 16 par défaut.

Quand tu assembles plusieurs services (Stripe, Sanity, Algolia, Supabase…), faire les appels directement depuis le client pose problèmes :

  • Clés API exposées (sauf si publishable).
  • Logique métier dispersée côté client.
  • Latence cumulée (4 round-trips au lieu de 1).

Solution : un BFF = une fine couche serveur dédiée à ton frontend qui orchestre les services tiers.

flowchart LR
    Client[Client browser] -->|1 appel| BFF[BFF<br/>Next.js Route Handler<br/>ou Hono / Fastify]
    BFF --> Stripe
    BFF --> Sup[Supabase]
    BFF --> Algolia
    BFF --> AI[OpenAI/Anthropic]
    BFF --> Resend
BFF — orchestre les services tiers
// app/api/checkout/route.ts (Next.js)
import Stripe from 'stripe';
import { auth } from '@clerk/nextjs/server';
import { supabase } from '@/lib/supabase';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
// 1. Auth
const { userId } = await auth();
if (!userId) return Response.json({ error: 'Unauthorized' }, { status: 401 });
// 2. Récupérer infos user depuis Supabase
const { data: user } = await supabase
.from('users')
.select('email, name, stripe_customer_id')
.eq('id', userId)
.single();
// 3. Créer la session Stripe
const session = await stripe.checkout.sessions.create({
customer: user.stripe_customer_id,
line_items: [{ price: 'price_xxx', quantity: 1 }],
mode: 'subscription',
success_url: `${origin}/success`,
cancel_url: `${origin}/cancel`,
});
// 4. Logger l'event dans Supabase
await supabase.from('checkout_events').insert({
user_id: userId,
session_id: session.id,
});
return Response.json({ url: session.url });
}

Le client appelle juste POST /api/checkout — propre, sécurisé, atomique.

Edge functions — pour la personnalisation et l’auth

Section intitulée « Edge functions — pour la personnalisation et l’auth »

L’edge est idéal pour 4 cas :

// middleware.ts (Next.js)
import { NextResponse } from 'next/server';
export function middleware(request) {
const session = request.cookies.get('session');
if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}

Exécuté avant la requête arrive au serveur applicatif. Latence ~10 ms.

export function middleware(request) {
const cookie = request.cookies.get('ab-test');
const variant = cookie?.value ?? (Math.random() > 0.5 ? 'A' : 'B');
const response = NextResponse.next();
response.cookies.set('ab-test', variant);
response.headers.set('x-variant', variant);
return response;
}
export function middleware(request) {
const country = request.geo?.country ?? 'US';
if (country === 'FR') {
return NextResponse.rewrite(new URL('/fr', request.url));
}
return NextResponse.next();
}

Avec Cloudflare KV ou Upstash Redis :

const ip = request.headers.get('x-forwarded-for')!;
const count = await redis.incr(`rate:${ip}`);
if (count === 1) await redis.expire(`rate:${ip}`, 60);
if (count > 100) return new Response('Rate limited', { status: 429 });

Inévitable un jour si ton produit grandit. Anticipe la migration dès le départ :

Tu commences avec Supabase complet. Plus tard, tu déplaces juste l’auth dans un service dédié, puis la DB vers un Postgres self-hosted, etc.

Tu mets un proxy / BFF entre client et backend. Le proxy route au BaaS pour les anciennes features, à ton nouveau backend pour les nouvelles. Migration progressive, sans downtime.

Pendant la transition, tu écris dans les deux systèmes (ancien BaaS + nouveau backend). Tu lis depuis le nouveau, valides, puis arrêtes l’écriture dans l’ancien.

C’est la raison pour laquelle on préfère Supabase à Firebase : Supabase = PostgreSQL standard. Ton schéma + tes données + tes RLS migrent directement vers un Postgres self-hosted (Neon, AWS RDS, ton VPS).

Firebase = Firestore propriétaire. Migration = réécrire tout le modèle de données.

ScénarioArchitecture suggérée
MVP solo, 1 mois pour livrerNext.js + Supabase + Clerk + Stripe + Vercel — tout BaaS
SaaS PME, équipe 5 devsNext.js + Supabase + Clerk + Stripe + Sentry + PostHog — composable
App mobile + webFirebase (cohérence native) + frontend custom
Site marketing / blogAstro + CMS headless (Sanity) + Vercel — pure JAMstack
App temps réel (chat, collab)Cloudflare Workers + Durable Objects + Supabase
Outil interne entrepriseBackend custom (Django/Symfony) + DB on-prem
Tu intègres Stripe, Supabase, Resend, OpenAI dans une SPA. Tu fais les appels directement depuis le client. Problème ?
Tu as choisi Firebase pour ton MVP. 2 ans plus tard, tu veux migrer vers Postgres self-hosted. Difficulté ?
Tu as un site marketing + blog (40 pages). Approche idéale en 2026 ?
  • JAMstack.orgjamstack.org
  • Sam Newman — Pattern: Backend for Frontend — articles de référence
  • Strangler Fig pattern — Martin Fowler
  • Patterns.dev — Rendering Patternspatterns.dev

Suite : 10.5 — Sécurité dans un BaaS — RLS, Security Rules, App Check.