ITSkillsCenter
Blog

Bun + Hono advanced : middleware custom et routes typées — tutoriel 2026

24 دقائق للقراءة



Bun + Hono advanced : middleware custom et routes typées — tutoriel 2026

Bun + Hono advanced : middleware custom et routes typées — tutoriel 2026

Cluster : Frameworks backend 2026 pour PME francophone : Rust Axum, Go Fiber, Elixir Phoenix
Cet article fait partie du cluster Backend modernes. Pour la vue d’ensemble complète des frameworks backend en 2026, commencez par lire le pilier du cluster.

Introduction

Imaginez un développeur à Abidjan ou à Dakar qui doit livrer une API REST pour son client PME en moins d’une semaine. Il n’a pas le temps de configurer un écosystème Node.js complexe avec webpack, ts-node, nodemon et une dizaine de dépendances de configuration. Il a besoin d’un outillage qui démarre immédiatement, qui comprend TypeScript nativement, et dont les performances tiennent la route même sur un VPS à 5 € par mois. C’est exactement la promesse de Bun combiné à Hono.

Bun est un runtime JavaScript tout-en-un écrit en Zig et propulsé par JavaScriptCore (le moteur de Safari d’Apple). Contrairement à Node.js qui repose sur V8, JavaScriptCore offre des temps de démarrage dramatiquement réduits — les processus Bun démarrent environ quatre fois plus vite que leurs équivalents Node.js selon les benchmarks officiels publiés sur bun.sh. Bun comprend TypeScript et JSX nativement, sans qu’il soit nécessaire d’installer un compilateur séparé ou de maintenir un fichier tsconfig.json complexe.

Hono, de son côté, est un framework web ultra-léger entièrement écrit en TypeScript et conçu autour des Web Standards (Fetch API, Response, Request). Sa philosophie est radicalement différente d’Express : zéro dépendance tierce dans son cœur, compatibilité native avec les environnements edge (Cloudflare Workers, Bun, Deno, AWS Lambda), et un système de routes qui tire pleinement parti du système de types de TypeScript. Le résultat est une API où les paramètres de route, les corps de requête validés et les réponses sont tous typés statiquement — les erreurs sont détectées à la compilation, pas en production à 3h du matin.

Ce tutoriel vous guide pas à pas, de l’initialisation du projet jusqu’au déploiement en production, en passant par la création de middleware custom pour le rate limiting, le CORS et le logging, la validation de schémas avec Zod, les routes groupées avec paramètres typés, et l’authentification par JWT. Chaque étape est expliquée dans son contexte pour qu’à la fin vous compreniez non seulement comment faire, mais pourquoi ces choix techniques sont pertinents pour une PME ouest-africaine en 2026.

Prérequis

  • Bun 1.1 minimum (Bun 1.2+ recommandé pour les fonctionnalités SQL natives et les améliorations Node.js) — voir bun.sh/docs/installation
  • Connaissance TypeScript intermédiaire — vous savez ce qu’est un générique, une interface, un type union
  • Bases HTTP — vous comprenez la différence entre GET, POST, PUT, DELETE et ce qu’est un header
  • Terminal Unix — les commandes sont données pour bash/zsh (Linux/macOS). Sous Windows, WSL2 est recommandé
  • Temps estimé : environ 30 minutes pour suivre toutes les étapes

Pour installer Bun, si vous ne l’avez pas encore, la commande officielle est la suivante :

# Linux / macOS
curl -fsSL https://bun.sh/install | bash

# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

Vérifiez l’installation avec bun --version. Vous devriez voir un numéro de version supérieur ou égal à 1.1.0. Si vous êtes sur Bun 1.2+, vous bénéficierez en bonus des améliorations de compatibilité Node.js et du client Postgres natif, même si ce tutoriel ne les exploite pas directement.

Étape 1 — Pourquoi Bun + Hono pour une PME ?

Avant de taper la première commande, prenons trois minutes pour comprendre pourquoi cette combinaison est particulièrement adaptée au contexte des PME, notamment en Afrique de l’Ouest où les contraintes sont réelles : serveurs mutualisés ou VPS d’entrée de gamme, développeurs souvent seuls ou en petite équipe, besoin de livrer vite et de maintenir facilement.

Performance dès le démarrage. Bun démarre en quelques dizaines de millisecondes grâce à JavaScriptCore. C’est crucial dans deux scénarios courants pour les PME : les fonctions serverless (où chaque invocation à froid compte) et les scripts d’automatisation qui doivent s’exécuter rapidement. Express sur Bun est trois fois plus rapide que sur Node.js selon les benchmarks de Bun 1.2. Avec Hono, qui n’ajoute quasiment aucun overhead, les performances sont encore meilleures.

TypeScript first, sans configuration. L’un des points de friction majeurs avec Node.js + TypeScript est la chaîne de build : installer typescript, ts-node ou tsx, configurer tsconfig.json, gérer les chemins, les source maps… Avec Bun, vous créez un fichier index.ts et vous tapez bun run index.ts. C’est tout. Pas de compilation préalable, pas de watch mode à configurer manuellement. Pour un développeur seul qui gère à la fois le backend, le frontend et l’infra, c’est des heures économisées chaque semaine.

Edge-ready par design. Hono a été conçu dès le départ pour fonctionner dans des environnements edge comme Cloudflare Workers, Fastly Compute ou Deno Deploy. Ces plateformes proposent des points de présence dans des régions stratégiques, dont l’Afrique subsaharienne via Cloudflare. Une API déployée sur Cloudflare Workers edge Lagos ou Johannesburg répondra avec une latence de 20 à 50 ms pour un utilisateur à Dakar, contre 150 à 300 ms pour un serveur hébergé en Europe. Sans modifier une ligne de code, votre application Hono peut basculer de Bun local vers Cloudflare Workers pour la production.

Hono et les types RPC. Hono propose un mode RPC optionnel où le client TypeScript peut inférer automatiquement les types des endpoints de l’API. Cela signifie que si vous changez le type de retour d’un endpoint, votre frontend TypeScript compilera en erreur immédiatement. Ce niveau de safety est normalement réservé à des outils complexes comme tRPC — Hono l’offre avec une API beaucoup plus simple.

Étape 2 — Initialisation du projet avec bun init

La commande bun init initialise un projet JavaScript ou TypeScript en interactif. Elle crée un package.json, un tsconfig.json minimaliste, et un fichier d’entrée. Pour un projet Hono, nous allons l’utiliser puis installer les dépendances nécessaires.

# Créer le dossier du projet et entrer dedans
mkdir mon-api-hono && cd mon-api-hono

# Initialiser le projet (répondre aux questions interactives)
bun init

# Installer Hono (le framework)
bun add hono

# Installer le validateur Zod pour Hono (middleware officiel)
bun add @hono/zod-validator zod

# Installer le middleware JWT de Hono
bun add @hono/jwt

# Dépendance de développement uniquement : types pour les environnements Bun
bun add -d @types/bun

Après ces commandes, votre package.json contiendra les quatre dépendances principales. Le fichier bun.lock (format texte JSONC lisible sur GitHub depuis Bun 1.2) verrouille les versions exactes. La structure initiale du projet est volontairement minimaliste : pas de dossier dist, pas de script de build complexe, juste un point d’entrée TypeScript que Bun exécute directement. Créez la structure de fichiers suivante :

mon-api-hono/
├── src/
│   ├── index.ts          # Point d'entrée principal
│   ├── middleware/
│   │   ├── logger.ts     # Middleware de logging
│   │   ├── rateLimit.ts  # Middleware rate limiting
│   │   └── cors.ts       # Middleware CORS custom
│   └── routes/
│       ├── users.ts      # Routes utilisateurs
│       └── products.ts   # Routes produits
├── package.json
├── bun.lock
└── tsconfig.json

Cette organisation sépare clairement les préoccupations : les middlewares transversaux dans src/middleware/ et les routes métier dans src/routes/. C’est une convention simple, pas un framework imposé — vous l’adaptez à la taille de votre projet.

Étape 3 — Premier handler avec validation Zod

Créons le fichier src/index.ts avec un premier endpoint GET et POST fonctionnels. L’objectif de cette étape est double : découvrir la syntaxe de base de Hono et comprendre comment le validateur Zod s’intègre pour valider les corps de requête avant qu’ils n’atteignent votre logique métier.

// src/index.ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

// Instanciation de l'application Hono
// Le générique <{ Variables: {} }> définit les variables de contexte (utile pour les middlewares)
const app = new Hono()

// Schéma Zod pour valider le corps d'une requête POST
const createUserSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.string().email(),
  role: z.enum(['admin', 'user', 'moderator']).default('user'),
})

// Route GET simple — retourne un objet JSON
app.get('/', (c) => {
  return c.json({ message: 'API opérationnelle', version: '1.0.0' })
})

// Route POST avec validation Zod intégrée
// Si la validation échoue, Hono retourne automatiquement un 400 avec les erreurs
app.post(
  '/users',
  zValidator('json', createUserSchema),  // middleware de validation
  async (c) => {
    // À ce stade, c.req.valid('json') est garanti être conforme au schéma
    const body = c.req.valid('json')
    // body.name, body.email, body.role sont tous typés
    return c.json({ success: true, user: body }, 201)
  }
)

// Démarrage du serveur sur le port 3000
export default {
  port: 3000,
  fetch: app.fetch,
}

Pour démarrer le serveur, exécutez bun run src/index.ts. Bun affiche le port d’écoute et le serveur est prêt en quelques dizaines de millisecondes. Testez avec curl http://localhost:3000/ — vous devez voir {"message":"API opérationnelle","version":"1.0.0"}. Pour tester la validation, envoyez un POST avec un email invalide : curl -X POST http://localhost:3000/users -H 'Content-Type: application/json' -d '{"name":"Ali","email":"pas-un-email"}' — Hono retourne un 400 avec le détail de l’erreur Zod. Le point fort de cette intégration est que c.req.valid('json') retourne un type TypeScript inféré directement depuis votre schéma Zod : pas de as any, pas de cast manuel.

Étape 4 — Middleware custom : rate limit, CORS, logger

Un middleware dans Hono est une fonction qui reçoit le contexte c et la fonction next, exécute du code avant et/ou après le handler principal, et peut court-circuiter la chaîne en renvoyant une réponse directement. C’est le même modèle que dans Express ou Koa, mais avec une signature 100 % typée. Nous allons créer trois middlewares custom : un logger structuré, un rate limiter en mémoire simple, et une configuration CORS précise.

// src/middleware/logger.ts
import { MiddlewareHandler } from 'hono'

export const customLogger = (): MiddlewareHandler => async (c, next) => {
  const start = Date.now()
  const method = c.req.method
  const path = c.req.path

  // Exécuter le reste de la chaîne middleware + handler
  await next()

  // Après la réponse : calculer la durée et logger
  const duration = Date.now() - start
  const status = c.res.status
  const timestamp = new Date().toISOString()

  // Format JSON structuré — facilement parsé par un outil de log centralisé
  console.log(JSON.stringify({ timestamp, method, path, status, duration_ms: duration }))
}
// src/middleware/rateLimit.ts
import { MiddlewareHandler } from 'hono'
import { HTTPException } from 'hono/http-exception'

// Store en mémoire : Map
const store = new Map()

interface RateLimitOptions {
  windowMs: number    // durée de la fenêtre en millisecondes
  maxRequests: number // nombre maximum de requêtes par fenêtre
}

export const rateLimit = (options: RateLimitOptions): MiddlewareHandler => {
  const { windowMs, maxRequests } = options

  return async (c, next) => {
    // Identifier le client par son IP (X-Forwarded-For en production derrière un proxy)
    const ip = c.req.header('x-forwarded-for') ?? c.req.header('x-real-ip') ?? 'unknown'
    const now = Date.now()

    const record = store.get(ip)

    if (!record || now > record.resetAt) {
      // Première requête ou fenêtre expirée : initialiser
      store.set(ip, { count: 1, resetAt: now + windowMs })
      return next()
    }

    if (record.count >= maxRequests) {
      // Limite atteinte : retourner 429 Too Many Requests
      throw new HTTPException(429, { message: 'Trop de requêtes, réessayez plus tard.' })
    }

    // Incrémenter le compteur et continuer
    record.count++
    return next()
  }
}
// src/middleware/cors.ts
import { cors } from 'hono/cors'

// Configuration CORS adaptée à un contexte PME ouest-africain :
// origines autorisées explicitement listées, méthodes restreintes au nécessaire
export const corsConfig = cors({
  origin: [
    'https://monsite.sn',
    'https://app.monsite.ci',
    'http://localhost:5173',  // Vite en développement local
  ],
  allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowHeaders: ['Content-Type', 'Authorization'],
  exposeHeaders: ['X-Request-Id'],
  maxAge: 86400,  // Cache preflight 24h
  credentials: true,
})

Une fois ces middlewares créés, on les applique dans src/index.ts. L’ordre d’application est important : le logger doit être en premier pour capturer toutes les requêtes, le rate limiter ensuite pour couper tôt les abus, puis le CORS pour les headers de réponse.

// Dans src/index.ts, ajoutez au-dessus des routes :
import { customLogger } from './middleware/logger'
import { rateLimit } from './middleware/rateLimit'
import { corsConfig } from './middleware/cors'

// app.use() applique un middleware à TOUTES les routes
app.use('*', customLogger())
app.use('*', rateLimit({ windowMs: 60_000, maxRequests: 100 }))
app.use('*', corsConfig)

Le middleware de rate limiting en mémoire convient parfaitement pour un seul processus Bun. Si vous passez à plusieurs instances (cluster ou Kubernetes), il faut externaliser le store vers Redis — nous l’évoquons dans la section FAQ. La gestion des erreurs globale via HTTPException de Hono garantit que vos 429 sont toujours retournés avec le bon format JSON, cohérent avec le reste de l’API.

Étape 5 — Routes groupées et paramètres typés

Hono propose un objet Hono qui peut être monté sur un autre objet Hono via app.route(). C’est le mécanisme de routage groupé — équivalent des Router d’Express mais avec une inférence de type complète sur les paramètres de route. Voici comment structurer les routes utilisateurs avec des paramètres typés.

// src/routes/users.ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

// Typage explicite des paramètres de route : ":id" est typé comme string
// Hono infère automatiquement le type depuis le pattern de la route
const users = new Hono()

// Schémas de validation réutilisables
const userParamSchema = z.object({ id: z.string().uuid() })
const updateUserSchema = z.object({
  name: z.string().min(2).max(100).optional(),
  email: z.string().email().optional(),
})

// GET /users — liste paginée avec validation des query params
users.get(
  '/',
  zValidator('query', z.object({
    page: z.coerce.number().int().positive().default(1),
    limit: z.coerce.number().int().min(1).max(100).default(20),
  })),
  async (c) => {
    const { page, limit } = c.req.valid('query')
    // Simulation d'une liste paginée
    return c.json({
      data: [],
      pagination: { page, limit, total: 0 }
    })
  }
)

// GET /users/:id — récupération d'un utilisateur par UUID
users.get(
  '/:id',
  zValidator('param', userParamSchema),
  async (c) => {
    const { id } = c.req.valid('param')  // id est garanti UUID valide
    // En production : requête base de données ici
    return c.json({ id, name: 'Moussa Diallo', email: 'moussa@example.sn' })
  }
)

// PUT /users/:id — mise à jour partielle
users.put(
  '/:id',
  zValidator('param', userParamSchema),
  zValidator('json', updateUserSchema),
  async (c) => {
    const { id } = c.req.valid('param')
    const updates = c.req.valid('json')
    return c.json({ id, ...updates, updatedAt: new Date().toISOString() })
  }
)

// DELETE /users/:id
users.delete(
  '/:id',
  zValidator('param', userParamSchema),
  async (c) => {
    const { id } = c.req.valid('param')
    return c.json({ success: true, deletedId: id })
  }
)

export { users }

Dans src/index.ts, montez ce routeur avec un préfixe :

import { users } from './routes/users'

// Toutes les routes du fichier users.ts seront préfixées par /api/v1/users
app.route('/api/v1/users', users)

Le grand avantage par rapport à Express est que c.req.valid('param') retourne un type TypeScript précis, inféré depuis votre schéma Zod. Si vous ajoutez un champ au schéma et oubliez de le gérer dans le handler, TypeScript vous le signale à la compilation. Ce feedback immédiat est précieux dans un contexte où les revues de code sont rares par manque de ressources.

Étape 6 — JWT et middleware d’authentification

L’authentification par JSON Web Token est le standard de facto pour les APIs REST sans état. Hono propose un middleware JWT officiel via le package @hono/jwt qui s’intègre proprement dans la chaîne de middleware. L’idée est d’appliquer la vérification JWT uniquement sur les routes protégées, pas sur les routes publiques comme la connexion ou l’inscription.

// src/middleware/auth.ts
import { jwt } from '@hono/jwt'
import { Hono } from 'hono'

// La clé secrète doit venir d'une variable d'environnement, jamais hardcodée
const JWT_SECRET = process.env.JWT_SECRET ?? 'changez-moi-en-production'

// Middleware JWT Hono : vérifie le header Authorization: Bearer 
// En cas d'échec, retourne automatiquement 401 avec message d'erreur
export const jwtMiddleware = jwt({ secret: JWT_SECRET })

// Utilitaire pour générer un token (utilisé dans le endpoint /auth/login)
export async function generateToken(payload: Record): Promise {
  const { sign } = await import('hono/jwt')
  return sign({ ...payload, exp: Math.floor(Date.now() / 1000) + 86400 }, JWT_SECRET)
}
// Dans src/routes/auth.ts — endpoint de connexion
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
import { generateToken } from '../middleware/auth'

const auth = new Hono()

const loginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
})

auth.post('/login', zValidator('json', loginSchema), async (c) => {
  const { email, password } = c.req.valid('json')

  // En production : vérifier contre la base de données avec bcrypt
  // Ici simulation simple
  if (email !== 'admin@example.sn' || password !== 'motdepasse123') {
    return c.json({ error: 'Identifiants incorrects' }, 401)
  }

  const token = await generateToken({ sub: '1', email, role: 'admin' })
  return c.json({ token, expiresIn: 86400 })
})

export { auth }
// Application du middleware JWT sur les routes protégées dans src/index.ts
import { jwtMiddleware } from './middleware/auth'
import { auth } from './routes/auth'

// Routes publiques (pas de JWT requis)
app.route('/api/v1/auth', auth)

// Routes protégées : le JWT est vérifié AVANT d'atteindre les handlers
app.use('/api/v1/users/*', jwtMiddleware)
app.use('/api/v1/products/*', jwtMiddleware)

// Monter les routes protégées APRÈS le middleware
app.route('/api/v1/users', users)

L’ordre de déclaration dans Hono est crucial : app.use('/api/v1/users/*', jwtMiddleware) doit être déclaré avant app.route('/api/v1/users', users). Hono traite les middlewares et routes dans l’ordre de déclaration. Si vous inversez, les requêtes atteignent les handlers avant la vérification JWT. Une fois authentifié, vous pouvez accéder au payload du token depuis n’importe quel handler via c.get('jwtPayload') — Hono injecte automatiquement le payload décodé dans le contexte.

Étape 7 — Déploiement Bun en production

Bun propose deux approches de déploiement pour la production : le mode serveur classique sur VPS (avec un process manager comme PM2 ou le service systemd), et le bundle compilé via bun build --compile qui produit un binaire autonome. Pour une PME qui dispose d’un VPS Linux, voici la procédure recommandée.

# Sur votre machine de développement : compiler un binaire autonome
# Le binaire embarque Bun runtime + votre code — aucune dépendance requise sur le serveur
bun build --compile --minify src/index.ts --outfile mon-api

# Vérifier la taille du binaire (typiquement 50-100 Mo avec Bun embarqué)
ls -lh mon-api

# Transférer vers le serveur
scp mon-api user@votre-serveur.com:/opt/mon-api/

# Sur le serveur : configurer un service systemd
sudo nano /etc/systemd/system/mon-api.service
# Contenu du fichier systemd
[Unit]
Description=Mon API Hono sur Bun
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/mon-api
ExecStart=/opt/mon-api/mon-api
Restart=always
RestartSec=5
Environment=JWT_SECRET=votre-secret-tres-long-et-aleatoire
Environment=NODE_ENV=production
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
# Activer et démarrer le service
sudo systemctl daemon-reload
sudo systemctl enable mon-api
sudo systemctl start mon-api

# Vérifier le statut
sudo systemctl status mon-api

# Voir les logs en temps réel
sudo journalctl -u mon-api -f

Pour Nginx en reverse proxy devant votre API Bun, la configuration est standard. Ajoutez un vhost qui proxifie vers localhost:3000 avec les bons headers de forwarding pour que votre middleware de rate limit récupère les vraies IPs clients. Le binaire compilé par Bun démarre en moins de 50 ms, ce qui est idéal pour les environnements serverless comme Railway, Render ou Fly.io où vous payez uniquement le temps d’exécution.

Erreurs fréquentes

Erreur Cause probable Solution
Cannot find module 'hono' Package non installé ou lockfile corrompu Supprimer node_modules et relancer bun install
JWT 401 sur routes protégées Middleware JWT déclaré après app.route() Déplacer app.use() AVANT app.route() dans le fichier
Validation Zod retourne 200 même avec données invalides zValidator non passé en 2e argument du handler Vérifier la signature : app.post('/route', zValidator(...), handler)
CORS bloqué en développement http://localhost:5173 absent de la liste des origines Ajouter l’origine dans le tableau origin du middleware CORS
Rate limit déclenché en développement Fenêtre trop courte ou max trop bas Désactiver le rate limit en dev : if (process.env.NODE_ENV !== 'production') return next()
Le binaire compilé ne démarre pas sur le serveur Compilé pour la mauvaise architecture (ex: macOS ARM vers Linux x64) Utiliser --target=bun-linux-x64 lors de la compilation
c.req.valid('json') retourne undefined La cible de validation ne correspond pas ('json' vs 'form') S’assurer que le Content-Type de la requête est application/json et que le premier arg de zValidator est 'json'

Adaptation au contexte ouest-africain

Le contexte technique de l’Afrique de l’Ouest impose des contraintes spécifiques que l’architecture Bun + Hono gère remarquablement bien. Voici comment tirer parti de cette stack dans les conditions réelles du terrain.

Startup 50 ms idéal pour le serverless africain. Les plateformes serverless comme Cloudflare Workers, Railway ou Fly.io facturent à la requête et au temps d’exécution. Avec Bun, le cold start (démarrage à froid) d’une instance est de l’ordre de 30 à 80 ms selon la taille du projet. C’est crucial pour les PME dont le trafic est intermittent : une boutique en ligne sénégalaise peut avoir des pics de trafic lors de promotions ou de jours de paye (fin de mois), et très peu de trafic le reste du temps. Le mode serverless avec Bun évite de payer un VPS allumé 24h/24 pour servir 10 requêtes par heure en dehors des heures de pointe.

Hono compatible Cloudflare Workers — edge à Lagos, Johannesburg, Dakar. Cloudflare dispose de points de présence (PoP) à Lagos (Nigeria), Johannesburg (Afrique du Sud), Nairobi (Kenya) et Dakar (Sénégal). En déployant votre API Hono sur Cloudflare Workers, vos utilisateurs à Abidjan ou à Bamako obtiennent des réponses depuis le PoP le plus proche, avec une latence typique de 20 à 50 ms au lieu des 150 à 300 ms d’un serveur en Europe. La migration du code Bun local vers Cloudflare Workers ne nécessite quasiment aucune modification : Hono expose la même API, seule la configuration de déploiement change (via Wrangler CLI de Cloudflare).

Intégration Wave et CinetPay en TypeScript. Les deux solutions de paiement mobile les plus utilisées en Afrique de l’Ouest disposent d’APIs REST documentées. Avec Hono et Zod, vous pouvez créer des handlers typés pour les callbacks de paiement Wave (webhooks) et CinetPay (IPN — Instant Payment Notification) de façon sûre et maintenable. Le schéma Zod valide le payload reçu avant tout traitement, ce qui protège contre les malformations ou les tentatives de falsification. Voici le squelette d’un webhook Wave :

// Route de callback paiement Wave
const waveWebhookSchema = z.object({
  id: z.string(),
  status: z.enum(['succeeded', 'failed', 'cancelled']),
  amount: z.number().positive(),
  currency: z.literal('XOF'),
  reference: z.string(),
})

app.post('/webhooks/wave', zValidator('json', waveWebhookSchema), async (c) => {
  const payment = c.req.valid('json')
  if (payment.status === 'succeeded') {
    // Activer la commande en base de données
    await activateOrder(payment.reference)
  }
  return c.json({ received: true })
})

Bande passante et contraintes réseau. Sur un réseau mobile 3G ou dans une zone à connectivité instable, chaque milliseconde compte. Les réponses JSON de Hono sont compactes par défaut. Activez la compression gzip via le middleware Hono officiel (import { compress } from 'hono/compress' puis app.use('*', compress())) pour réduire la taille des réponses de 60 à 80 % sur des payloads JSON verbeux. Sur une connexion 3G à 1 Mbps, la différence entre une réponse de 50 Ko et 10 Ko est perceptible pour l’utilisateur final.

Tutoriels frères

Pour aller plus loin

FAQ

Q : Hono peut-il remplacer Express en production en 2026 ?
Oui, absolument. Hono est utilisé en production par des milliers de projets depuis 2023. Son écosystème de middleware officiel couvre les besoins les plus courants : CORS, JWT, compression, rate limiting, sessions, bearer auth, basic auth. La principale raison de rester sur Express serait un projet legacy avec des dizaines de middlewares Express tiers spécifiques — mais pour tout nouveau projet TypeScript, Hono est supérieur en performance et en expérience développeur.
Q : Le rate limiter en mémoire fonctionne-t-il si l’application tourne sur plusieurs instances ?
Non. Un Map en mémoire est local au processus. Si vous avez deux instances Bun derrière un load balancer, chacune maintient son propre compteur. Pour un rate limiting distribué, remplacez le store Map par un client Redis (via le package ioredis ou bun add redis) qui incrémente une clé avec TTL. La logique reste identique, seul le backend de stockage change.
Q : Comment déployer sur Cloudflare Workers sans modifier le code ?
Le code Hono est identique. Seul le point d’entrée change légèrement : au lieu de export default { port: 3000, fetch: app.fetch }, vous exportez export default app (Cloudflare Workers utilise directement l’objet Hono comme handler). Installez Wrangler CLI (bun add -g wrangler), créez un fichier wrangler.toml minimal, et lancez wrangler deploy. L’intégralité de la documentation est sur hono.dev/docs/getting-started/cloudflare-workers.
Q : Comment gérer les variables d’environnement avec Bun ?
Bun charge automatiquement les fichiers .env, .env.local, .env.production selon NODE_ENV. Pas besoin d’installer dotenv. Accédez aux variables via process.env.MA_VARIABLE ou Bun.env.MA_VARIABLE. En production avec un binaire compilé, les variables d’environnement sont injectées via systemd (Environment=) ou les variables d’environnement de la plateforme cloud.
Q : Hono supporte-t-il les WebSockets pour des applications temps réel ?
Oui, Hono supporte les WebSockets nativement sur Bun via le helper upgradeWebSocket. La syntaxe est simple et typée. Cependant, pour des applications nécessitant des dizaines de milliers de connexions WebSocket simultanées (chat, notifications push), Elixir Phoenix avec son modèle d’acteurs légers sera plus adapté. Bun + Hono WebSocket est idéal pour des besoins modérés comme les tableaux de bord avec mises à jour en temps réel.
Q : Peut-on utiliser Prisma ou Drizzle ORM avec Bun et Hono ?
Oui. Prisma fonctionne avec Bun depuis Prisma 5.x (avec quelques particularités dans la génération du client — consulter la documentation Prisma pour Bun). Drizzle ORM est recommandé par la communauté Bun car il est plus léger et ses migrations sont en TypeScript pur. Pour les projets Bun-first sans contrainte d’ORM, Bun.sql (depuis Bun 1.2) est le client PostgreSQL le plus performant, 50 % plus rapide que postgres.js.
Q : Bun est-il stable pour la production ou encore expérimental ?
Bun est stable pour la production depuis la version 1.0 (septembre 2023). La version 1.2 (janvier 2025) a marqué un tournant avec plus de 90 % de compatibilité avec la suite de tests Node.js. De nombreuses entreprises utilisent Bun en production. Les zones de vigilance restantes sont principalement les packages npm qui utilisent des bindings natifs C++ complexes — vérifiez la compatibilité sur la page bun.sh/nodejs-compat.



ملخص بالعربية: دليل تقني متقدم حول استخدام Bun 1.2 و Hono v4 لبناء واجهات برمجية سريعة بلغة TypeScript مع برمجيات وسيطة مخصصة ومسارات مُحكمة الأنواع، موجَّه لمطوري المؤسسات الصغيرة والمتوسطة في غرب إفريقيا.
Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité