bootstrapControllers(options)
Initializes controller routes and returns the Koa app and router used by Amala.
Promise<{app: Application; router: Router}>
Only controllers is required.
const {app, router} = await bootstrapControllers({
controllers: [HealthController, UserController],
});
Core options
| Option | Default | Purpose |
|---|---|---|
controllers | required | Trusted controller classes or glob strings to load. Prefer explicit classes. |
controllerFactory | Per-request new ControllerClass(ctx) | Resolve controller instances through an application-owned dependency injection container. |
app | new Koa app | Use an existing Koa application. |
router | new Koa router | Use an existing @koa/router instance. |
basePath | '' | Prefix added before version, controller, and OpenAPI paths. |
attachRoutes | false | Attach router.routes() and router.allowedMethods() automatically. |
flow | [] | Global Koa middleware registered before generated routes. |
diagnostics | false | Log controller and route registration details. Avoid in noisy production logs. |
Controller glob strings are executed with require() at startup. Never derive them from request data or another untrusted source.
Versioning
Versioning is enabled by default with version 1.
versions: [1, 2]
This registers compatible endpoints under /v1 and /v2. An object can also mark a version as deprecated:
versions: {
1: 'Version 1 will be removed on 2027-01-01.',
2: true,
}
Amala includes that message in the Deprecation response header for version 1 routes. Set disableVersioning: true to omit the /v... path segment. @Version handlers are skipped when built-in versioning is disabled.
Request parsing
Amala configures koa-body unless bodyParser is false.
bodyParser: {
formLimit: '56kb',
jsonLimit: '1mb',
multipart: false,
textLimit: '56kb',
}
Multipart parsing remains enabled by default for compatibility. Explicitly set multipart: false when uploads are not needed. When uploads are enabled, configure formidable limits and validate file content in application code.
Set bodyParser: false if the application installs its own parser.
Validation
validatorOptions is passed to class-validator whenever Amala receives a decorated class input:
validatorOptions: {
forbidNonWhitelisted: true,
whitelist: true,
}
Interfaces do not exist at runtime and cannot be validated. Use a class with class-validator decorators.
Dependency injection
By default, Amala constructs a fresh controller for each request and passes the Koa context to its constructor. Set controllerFactory to resolve that request's controller from a dependency injection container instead:
const {app} = await bootstrapControllers({
controllers: [UserController],
flow: [async (ctx, next) => {
const scope = container.createScope();
try {
ctx.state.container = scope;
await next();
} finally {
await scope.dispose();
}
}],
controllerFactory: (ControllerClass, ctx) =>
ctx.state.container.resolve(ControllerClass),
});
The factory receives the controller class and current Koa context, may return a promise, and runs once per request. Amala does not store a global container or dispose application-owned scopes. Create and clean up request scopes in middleware so concurrent requests cannot share request-specific state accidentally.
OpenAPI
OpenAPI generation is enabled by default.
openAPI: {
enabled: true,
publicURL: 'https://api.example.com',
specPath: 'docs',
webPath: 'swagger',
spec: {
info: {
title: 'Example API',
version: '1.0.0',
},
},
}
specPath and webPath are appended to basePath. With basePath: '/api', their defaults are /api/docs and /api/swagger. publicURL defaults to the current origin.
In the generated document, each server URL owns the API basePath and version prefix. Paths remain relative to that server, preventing clients from repeating the base path.
Set openAPI: {enabled: false} to disable both endpoints. In production, disable them or apply access-control middleware if the API inventory is sensitive.
HTTP security headers
Set useHelmet: true to add Koa Helmet to the global middleware flow, or pass Helmet options:
useHelmet: {
contentSecurityPolicy: false,
}
Review Helmet options for your application, especially when serving Swagger UI from the same process.
CORS
CORS is enabled by default using @koa/cors defaults. Public applications should configure an explicit allowed origin or disable Amala's CORS middleware and install their own policy:
cors: {
enabled: true,
opts: {
credentials: true,
origin: 'https://app.example.com',
},
}
Do not combine credentialed requests with a wildcard origin.
Error handling
The default handler formats Boom errors, returns validation details for client errors, and hides details for server errors. Override it with errorHandler when you need structured logging or a different response envelope:
errorHandler: async (error, ctx) => {
ctx.status = error.status ?? 500;
ctx.body = {error: ctx.status < 500 ? error.message : 'Internal Server Error'};
}
Keep secrets, request bodies, authorization headers, and raw third-party URLs out of error logs.
Bring your own app or router
const {app, router} = await bootstrapControllers({
app: koaApp,
router: koaRouter,
controllers: [HealthController],
});
The same objects are returned after Amala registers its middleware and routes.