Fonctions Personnalisées
Overview
Section intitulée « Overview »Les fonctions personnalisées vous permettent d’ajouter des routes d’API Hono arbitraires aux côtés des points de terminaison CRUD auto-générés de Rebase. Elles suivent le même modèle de découverte basée sur les fichiers que les collections et les tâches cron : déposez un fichier TypeScript dans votre répertoire functions/, et Rebase le monte automatiquement.
Utilisez les fonctions personnalisées pour :
- Points de terminaison de logique métier — approbations, promotions, workflows personnalisés
- Intégrations tierces — webhooks Stripe, commandes Slack, proxys d’API externes
- Points de terminaison publics — formulaires de contact, capture de leads, vérifications de l’état de santé
- Requêtes agrégées — statistiques de tableau de bord, rapports, analyses
Définir une fonction personnalisée
Section intitulée « Définir une fonction personnalisée »Créez un fichier dans votre répertoire backend/functions/ qui exporte par défaut une application Hono :
// backend/functions/hello.tsimport { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => { return c.json({ message: "Hello from custom function!" });});
export default app;Ceci est monté à /api/functions/hello. Le nom de fichier (sans extension) devient le préfixe de la route.
Configuration
Section intitulée « Configuration »Activez les fonctions personnalisées en ajoutant functionsDir à votre configuration de backend :
import path from "path";
const instance = await initializeRebaseBackend({ // ... other config functionsDir: path.resolve(__dirname, "../functions"),});Rebase va :
- Scanner le répertoire pour les fichiers
.ts/.js - Valider que chaque exportation par défaut est une application Hono (duck-typed via
.fetch()+.routes) - Monter chaque application à
/api/functions/<filename> - Appliquer le middleware d’authentification (voir Authentification ci-dessous)
Nommage des fichiers et mappage des routes
Section intitulée « Nommage des fichiers et mappage des routes »| Fichier | Chemin de montage |
|---|---|
functions/hello.ts | /api/functions/hello/* |
functions/send-invoice.ts | /api/functions/send-invoice/* |
functions/webhooks.ts | /api/functions/webhooks/* |
Fichiers qui sont ignorés :
index.ts/index.js— réservé*.test.ts/*.test.js— fichiers de test*.d.ts— déclarations de type
Export Formats
Section intitulée « Export Formats »Le chargeur accepte deux formats d’exportation :
Application Hono (recommandé)
Section intitulée « Application Hono (recommandé) »import { Hono } from "hono";const app = new Hono();app.get("/status", (c) => c.json({ ok: true }));export default app;Fonction Fabrique
Section intitulée « Fonction Fabrique »import { Hono } from "hono";export default function () { const app = new Hono(); app.get("/status", (c) => c.json({ ok: true })); return app;}Les deux sont détectés via le duck-typing — le chargeur vérifie les propriétés .fetch() et .routes, de sorte que toute instance compatible Hono fonctionnera quelle que soit la version de Hono installée.
Authentication
Section intitulée « Authentication »Les fonctions personnalisées sont montées avec le même middleware d’authentification que les routes de données, mais avec requireAuth: false. Cela signifie :
- Le JWT de l’utilisateur est analysé et injecté dans le contexte s’il est présent
- Mais les requêtes ne sont pas rejetées si aucun JWT n’est fourni
- Vous devez protéger explicitement les routes qui nécessitent une authentification
Protection des routes
Section intitulée « Protection des routes »Utilisez les assistants d’authentification intégrés de Rebase :
import { Hono } from "hono";
const app = new Hono();
// Public endpoint — no auth requiredapp.get("/public", (c) => { return c.json({ message: "Anyone can access this" });});
// Protected endpoint — requires a valid JWTapp.post("/protected", async (c) => { const user = c.get("user"); // Injected by Rebase middleware if (!user) { return c.json({ error: "Unauthorized" }, 401); } return c.json({ message: `Hello, ${user.uid}` });});
// Admin-only endpointapp.post("/admin-only", async (c) => { const user = c.get("user"); const roles: string[] = user?.roles ?? []; if (!roles.includes("admin")) { return c.json({ error: "Admin access required" }, 403); } return c.json({ message: "Admin operation succeeded" });});
export default app;Le middleware JWT de Rebase est limité aux routes API intégrées (/api/data, /api/auth, etc.). Les routes de fonctions personnalisées obtiennent le contexte utilisateur analysé, mais vous devez appliquer le contrôle d’accès vous-même.
Accès à la base de données
Section intitulée « Accès à la base de données »Les fonctions personnalisées s’exécutent aux côtés de Rebase, vous pouvez donc accéder à la base de données via deux approches :
1. Via le Singleton Rebase (Recommandé)
Section intitulée « 1. Via le Singleton Rebase (Recommandé) »Le package @rebasepro/server-core fournit un singleton rebase qui vous donne un accès de niveau administrateur à tous les services (données, authentification, stockage, e-mail) liés à l’application, depuis n’importe où dans votre backend.
// backend/functions/approve-job.tsimport { Hono } from "hono";import { rebase } from "@rebasepro/server-core";
const app = new Hono();
app.post("/:id/approve", async (c) => { const id = c.req.param("id");
// Use the admin-level data API (bypasses RLS) await rebase.data.saveEntity("jobs", { id, status: "published", approved_at: new Date().toISOString(), });
return c.json({ success: true });});
export default app;2. Via l’Accès Direct à Drizzle
Section intitulée « 2. Via l’Accès Direct à Drizzle »// backend/functions/reports.tsimport { Hono } from "hono";import { db } from "../src/db"; // Your Drizzle instanceimport { sql } from "drizzle-orm";
const app = new Hono();
app.get("/stats", async (c) => { const result = await db.execute(sql` SELECT COUNT(*) as total FROM jobs WHERE status = 'published' `); return c.json({ totalJobs: result.rows[0]?.total });});
export default app;Ordre d’enregistrement des routes
Section intitulée « Ordre d’enregistrement des routes »Les fonctions personnalisées sont chargées et montées après que initializeRebaseBackend() ait terminé la configuration principale. L’ordre d’initialisation est :
- Bootstrappers — Connexions à la base de données, tables d’authentification, services en temps réel
- Routes d’authentification —
/api/auth/*,/api/admin/* - Routes de stockage —
/api/storage/* - Routes de données —
/api/data/*(CRUD pour les collections) - Fonctions personnalisées ←
/api/functions/* - Tâches Cron —
/api/cron/* - WebSocket — Abonnements en temps réel
Cela signifie que vos fonctions personnalisées ont accès à tous les services initialisés. Enregistrez toutes les routes qui doivent s’exécuter avant Rebase directement sur l’application Hono, avant d’appeler initializeRebaseBackend() :
const app = new Hono();
// Ceci s'exécute AVANT les routes Rebaseapp.get("/health", (c) => c.json({ status: "ok" }));
// Initialisation de Rebase — enregistre toutes les routes /api/*const instance = await initializeRebaseBackend({ app, /* ... */ });Exemple : Gestionnaire de Webhook
Section intitulée « Exemple : Gestionnaire de Webhook »// backend/functions/stripe-webhook.tsimport { Hono } from "hono";import Stripe from "stripe";import { instance } from "../src/index";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);const app = new Hono();
app.post("/", async (c) => { const sig = c.req.header("stripe-signature")!; const body = await c.req.text();
const event = stripe.webhooks.constructEvent( body, sig, process.env.STRIPE_WEBHOOK_SECRET! );
if (event.type === "checkout.session.completed") { const session = event.data.object; await instance.driver.data.subscriptions.create({ user_id: session.client_reference_id, stripe_id: session.subscription, status: "active", }); }
return c.json({ received: true });});
export default app;Debugging
Section intitulée « Debugging »Lorsqu’une fonction est chargée avec succès, vous verrez :
⚡ Loaded function route: helloSi le chargement échoue, le chargeur fournit une sortie de diagnostic :
[functions] broken-function.ts: default export is not a Hono app or factory. Skipping. export type: object (SomeClass) prototype methods: constructor, someMethod Hint: ensure the function exports a Hono app created with the same hono version as the server.Prochaines Étapes
Section intitulée « Prochaines Étapes »- Présentation du Backend — Référence complète de la configuration du backend
- Callbacks d’Entité — Exécutez de la logique sur les modifications de données
- Tâches Cron — Tâches d’arrière-plan planifiées