CORE CONCEPTS
Bootstrap & ServerApp
bootstrap() is the recommended entry point for a Rasengan Server app. It creates a ServerApp, hands it to your callback for configuration, then compiles and serves it.
import { bootstrap } from '@rasenganjs/server'; bootstrap((app) => { app.registerModule(appModule); app.enableCors(); });
What bootstrap() Does
- Creates a
ServerAppinstance. - Loads configuration (
rasengan.server.ts, merged with any CLI overrides). - Invokes your callback, passing the
ServerAppfor configuration. - Calls
app.compile(), turning your modules/controllers into a runtimeFuton. - Selects the right runtime adapter (Node/Bun/Workerd) and starts serving.
- Registers
SIGTERM/SIGINThandlers for graceful shutdown.
function bootstrap( callback: (app: ServerApp) => void | Promise<void>, overrides?: Partial<RasenganServerConfig> ): Promise<ServerHandle>;
bootstrap() returns a ServerHandle ({ close(), app }) you can use to shut the server down programmatically — useful in tests.
ServerApp — the Orchestrator
ServerApp is the class your bootstrap() callback configures. It owns module registration, global middleware, error/404 handlers, and compiles everything into a Futon instance.
bootstrap((app) => { app.registerModule(appModule); app.enableCors({ origin: 'https://myapp.com' }); app.onError(async (error, ctx) => { return ctx.res.status(500).json({ error: error.message }); }); app.notFound(async (ctx) => { return ctx.res.status(404).json({ error: 'Not Found' }); }); });
Default Global Middleware
Every ServerApp starts with two middleware pre-registered, in this order: a request logger() and a bodyParser() (storing the parsed body under ctx.state.body). Anything you add via app.use() runs after these.
Middleware Execution Order
Rasengan Server layers middleware in a fixed order, regardless of where each layer is declared:
- Global —
app.use(),app.enableCors(), plus the default logger/body parser - Module-level —
ModuleConfig.middlewares, scoped to that module's routes - Controller-level —
Controller.middlewares, scoped to that controller's routes - Route-level — passed directly to
router.get(path, middleware, handler) - Validation — injected automatically for routes with schemas
- Handler — your route handler function
See Middleware for a worked example of each layer.
Compiling and Serving
app.compile() runs once, internally, as part of bootstrap() — you don't normally call it yourself. It flattens your module tree, registers every provider in a shared DI container, and registers every controller's routes with the correct middleware nesting. bootstrap() then hands the resulting Futon to whichever runtime adapter matches your preset.
configureBodyParser() exists in the class but is currently commented out in the source — the default bodyParser({ key: 'body' }) is always active and isn't yet swappable for custom options (size limits, allowed types). Worth checking back on if you need that control today.
