🚧 AvleonJs is in active development and not ready for production use.

Openapi Intregation

Generating API documentation from your controllers.

Avleon generates an OpenAPI document from your controllers and serves a browsable UI. Nothing extra to install — the Swagger integration ships with the core.

Enabling

npx avleon make:config openapi
config/openapi.config.ts
app.ts
import { AppConfig, AvleonConfig, Environment, OpenApiUiOptions } from '@avleon/core';

@AppConfig
export class OpenApiConfig extends AvleonConfig<OpenApiUiOptions> {
  config(env: Environment): OpenApiUiOptions {
    return {
      info: {
        title: 'My API',
        version: '1.0.0',
        description: 'API documentation',
      },
      routePrefix: '/docs',
    };
  }
}

The UI is then served at routePrefixhttp://localhost:4000/docs above.

useOpenApi also accepts a plain options object if you do not need a config class:

app.useOpenApi({
  info: { title: 'My API', version: '1.0.0' },
  routePrefix: '/docs',
});

Options

OptionDescription
infoTitle, version, description
routePrefixWhere the UI is served. Defaults to /docs
provider'default' (Swagger UI) or 'scalar'
serversServer URLs
tagsTag definitions
securityGlobal security requirements
componentsReusable schemas and security schemes

Scalar UI

To use Scalar instead of Swagger UI, set the provider — it ships with the core, so there is nothing extra to install:

app.useOpenApi({
  info: { title: 'My API', version: '1.0.0' },
  provider: 'scalar',
});

The CLI can wire this up for you — pick Scalar UI when running avleon new.

Documenting routes

Use @OpenApi on a controller or a route method to enrich the generated document.

controllers/welcome.controller.ts
import { ApiController, Get, OpenApi } from '@avleon/core';

@OpenApi({ tags: ['welcome'] })
@ApiController('/welcome')
export class WelcomeController {
  @OpenApi({
    summary: 'Say hello',
    description: 'Returns a greeting.',
    response: {
      200: { description: 'A greeting' },
    },
  })
  @Get()
  sayHello() {
    return 'Hello world!';
  }
}

Useful @OpenApi fields:

FieldDescription
summary / descriptionHuman-readable text
tagsGroups the route in the UI
params / query / headersDocument inputs
requestBodyDocument the body
responseResponses keyed by status code
deprecatedMark the route deprecated
excludeHide the route from the document
securityPer-route security requirements

For example, documenting inputs:

@OpenApi({
  params: { id: { type: 'string', example: 'abc-123' } },
  query: { page: { type: 'integer', example: 1 } },
})
@Get('/:id')
findOne(@Param('id') id: string) {
  return { id };
}

Inline routes

Routes registered with mapGet and friends return a chainable object, so they can carry their own OpenAPI metadata:

app.ts
import { Avleon } from '@avleon/core';

const app = Avleon.createApplication();

app.mapGet('/', () => 'Welcome to Avleon.').useOpenApi({
  tags: ['welcome'],
  summary: 'Root greeting',
});

export default app;

The same object also exposes useMiddleware:

app.mapGet('/secret', handler)
  .useMiddleware([ApiKeyMiddleware])
  .useOpenApi({ tags: ['internal'] });