Dev API

Pendant emberkit dev, EmberKit peut intercepter /api et /api/* et exécuter votre logique backend dans Node — sans serveur proxy séparé.

Quand l'utiliser

ApprocheIdéal pour
Basé sur fichiers src/routes/_api/*Handlers REST colocalisés avec les routes, similaire à Next.js Route Handlers
Module handler personnaliséRouteurs style Express existants, migrations Turso à la première requête, handleApiRequest partagé pour dev et Workers

Recommandé — emberkit.config.ts

import { defineConfig } from '@emberkit/core';
import { emberkitVitePlugin } from '@emberkit/core/vite-plugin';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  mode: 'ssr',
  devApi: {
    handler: './src/server/api-router.node.ts',
    export: 'handleApiRequestNode',
    prefix: '/api', // optional, default '/api'
  },
  vite: {
    plugins: [emberkitVitePlugin(), tailwindcss()],
  },
});

emberkitVitePlugin() automatiquement :

  • Charge devApi depuis ce fichier et enregistre le middleware dev
  • Active sqlRawPlugin pour imports *.sql?raw
  • Retombe sur src/routes/_api/* quand devApi est omis

Option B — plugins Vite explicites (avancé)

Nécessaire seulement si vous ne pouvez pas utiliser devApi dans emberkit.config.ts ou avez besoin d'un ordre de plugins personnalisé :

import {
  devApiPlugin,
  emberkitVitePlugin,
  sqlRawPlugin,
} from '@emberkit/core/vite-plugin';

export const appVitePlugins = [
  sqlRawPlugin(),
  devApiPlugin({
    handler: './src/server/api-router.node.ts',
    export: 'handleApiRequestNode',
  }),
  emberkitVitePlugin(),
];

Ne dupliquez pas devApi dans config et devApiPlugin en même temps.

Handler Node personnalisé

Exportez une fonction avec la signature IncomingMessage / ServerResponse de Node :

// src/server/api-router.node.ts
import type { IncomingMessage, ServerResponse } from 'node:http';
import { handleApiRequest } from './api-router.ts';

export async function handleApiRequestNode(
  req: IncomingMessage,
  res: ServerResponse,
): Promise<void> {
  const host = req.headers.host ?? 'localhost';
  const url = `http://${host}${req.url ?? '/'}`;
  const request = new Request(url, { method: req.method, headers: req.headers });
  const response = await handleApiRequest(request, env);
  // copy status, headers, body to res ...
}

Partagez handleApiRequest(request, env) entre dev (Node) et production (Workers) pour un comportement cohérent.

Utilisez createNodeDevApiHandler pour éviter de dupliquer le pont headers/cookies sûr :

import { createNodeDevApiHandler } from '@emberkit/core/vite-plugin';
import { handleApiRequest } from './api-router.ts';

export const handleApiRequestNode = createNodeDevApiHandler(
  handleApiRequest,
  () => ({
    TURSO_DATABASE_URL: process.env.TURSO_DATABASE_URL ?? '',
    // ...
  }),
);

Routes API basées sur fichiers

Ajoutez des handlers sous src/routes/_api/ :

src/routes/_api/
  health.ts      →  GET /api/health
  blog/
    list.ts      →  GET /api/blog/list

Quand devApi n'est pas défini en config et qu'au moins une route _api existe, EmberKit active automatiquement le routage dev API basé sur fichiers.

Routage des requêtes

  1. Le pathname de l'URL est /api ou commence par /api/.
  2. Le middleware dev s'exécute avant le rendu SSR des pages (SSR ignore les URLs API).
  3. Le module handler est chargé une fois via server.ssrLoadModule() et mis en cache.

Tests locaux

pnpm dev
curl -s "http://localhost:4321/api/health"
curl -s "http://localhost:4321/api/blog/list?lang=en"

Si le port est occupé, EmberKit choisit le suivant libre — consultez la bannière du dev server.

Exports Vite

Depuis @emberkit/core/vite-plugin :

ExportDescription
devApiPlugin(options)Plugin Vite pour handler personnalisé
registerDevApiMiddleware(server, options)Enregistrer middleware sur un dev server existant
registerFileBasedDevApiMiddleware(server)Enregistrer routage fichiers _api
isApiRequest(url)Retourne true pour /api et /api/*
incomingMessageToRequest(req)Convertir requête Node en Fetch Request
writeFetchResponseToNode(res, response)Écrire Fetch Response vers Node

Liens connexes