@nodeboot/express-sample is the flagship Express reference app in the Node-Boot monorepo. It boots ExpressServer from src/server.ts, wires the application in src/app.ts, and demonstrates how to assemble a production-style Node-Boot service with SQLite/TypeORM persistence, OpenAPI + Swagger UI, request validation, authorization hooks, scheduled jobs, HTTP clients, actuator support, and custom configuration classes. The sample also seeds demo data on startup, runs TypeORM migrations automatically, and includes custom middleware, listeners, and configuration beans.
In
app-config.yaml,api.routePrefixis/api, and every controller in this sample is declared with version"v1", so the controller routes resolve under/api/v1.
-
@NodeBootApplication()— defines the application entrypoint and boots the framework withNodeBoot.run(ExpressServer). See Core. -
@EnableDI(Container)— enables dependency injection with TypeDI for controllers, services, listeners, and resolvers. See DI. -
@EnableComponentScan()— enables AOT/component scanning so decorated classes are discovered automatically. See AOT. -
@EnableOpenApi()— generates OpenAPI metadata from controllers, DTOs, and response schemas. See OpenAPI starter. -
@EnableSwaggerUI()— exposes interactive Swagger UI for the generated OpenAPI spec. See OpenAPI starter. -
@EnableAuthorization(LoggedInUserResolver, DefaultAuthorizationResolver)— wires custom current-user and authorization checkers into controller security. See Authorization. -
@EnableActuator()— enables actuator/observability endpoints for runtime inspection. See Actuator starter. -
@EnableRepositories()— enables TypeORM-backed repositories, migrations, transactions, and entity subscribers. See Persistence starter. -
@EnableScheduling()— enables cron-style scheduled jobs via@Scheduler(...). See Scheduler starter. -
@EnableHttpClients()— enables typed outbound HTTP clients built with@HttpClient(...). See HTTP starter. -
@EnableValidations()— enables request validation usingclass-validatorDTOs. See Validation starter. - Express server adapter — uses
@nodeboot/express-serverwith route prefixing, middleware integration, multipart support, CORS, cookies, and sessions. See Express server. - Typed configuration properties —
AppConfigPropertiesbindsapp.*into a class, andConfigServiceis used from application code. See Config. - Custom configuration classes and beans — the sample registers Express middleware with
@Configuration()+@Bean(), groups config classes with@Configurations(...), and overrides datasource settings with annotations. - DTO/model metadata — DTOs use
class-validator, while response models use@Model()/@Property()metadata for schema generation.
- Node.js 18+
- pnpm (10.x recommended; the repo is pinned to
pnpm@10.17.1) - No external database required — this sample uses local SQLite through
better-sqlite3
pnpm installThe sample reads app-config.yaml and can layer local overrides from app-config.local.yaml.
Current configuration structure:
app:
name: facts-service
platform: tech-insights
environment: development
defaultErrorHandler: false
port: 3000
api:
routePrefix: /api
nullResultCode: 200
undefinedResultCode: 200
paramOptions:
required: false
validations:
enableDebugMessages: false
skipUndefinedProperties: false
skipNullProperties: false
skipMissingProperties: false
whitelist: false
forbidNonWhitelisted: false
forbidUnknownValues: true
stopAtFirstError: false
server:
cors: ...
multipart: ...
openapi:
info: ...
servers: ...
externalDocs: ...
securitySchemes:
basicAuth: ...
persistence:
type: better-sqlite3
synchronize: false
cache: true
migrationsRun: true
better-sqlite3:
database: express-sample.dbapp-config.local.yaml currently demonstrates a local-secret include pattern:
credentials:
$include: app-credentials.local.yamlKeep any real credentials in the included local file instead of committing them to app-config.yaml.
pnpm devpnpm dev runs nodemon, watches src/**, recompiles, rebuilds, and restarts the server using the real bootstrap entrypoint in src/server.ts.
pnpm testpnpm build
pnpm start
pnpm start:prodsrc/
├── app.ts # Main application class and feature-enabling decorators
├── server.ts # Real bootstrap entrypoint that creates and starts FactsServiceApp
├── auth/ # Demo CurrentUserChecker and AuthorizationChecker implementations
├── clients/ # Outbound HTTP client definitions
├── config/ # Typed config properties and @Configuration/@Bean examples
├── controllers/ # Versioned HTTP controllers and route handlers
├── http/ # Example HTTP request file for manual testing
├── middlewares/ # Before-request logging and custom error handling
├── models/ # DTOs and OpenAPI/validation models
├── persistence/ # Entities, repositories, migrations, listeners, datasource config, seed data
└── services/ # Business logic, scheduled jobs, and persistence/http integration
AppConfigProperties— bindsapp.*from configuration into a typed class.ServerConfiguration— exposes a server configuration bean that maps optionalcookie,cors,session, andmultipartsettings from config (the sample YAML currently configurescorsandmultipart).SecurityConfiguration— registershpp()andhelmet()on the Express application and disablesx-powered-by.ClassTransformConfiguration— demonstrates class-transformer configuration withexposeAllstrategies while the transformer feature is currently markedenabled: false.MultipleConfigurations— demonstrates grouping multiple configuration classes with@Configurations(...).DatasourceOverridesConfiguration— demonstrates annotation-based datasource overrides for SQLite (better-sqlite3, migrations on, sync off).
GET /api/v1/hello/— returns the plain stringHello, World!.GET /api/v1/hello— returns a simple object payload with arbitrary properties.GET /api/v1/hello/complex— returns aSampleModel-shaped response and demonstrates OpenAPI model metadata.
GET /api/v1/users/— list all persisted users.GET /api/v1/users/external/— fetch users from the external demo API viaMicroserviceHttpClient.GET /api/v1/users/query/— run the repository's custom query-builder example (id IN (1, 2)).GET /api/v1/users/:id— fetch a user by id.POST /api/v1/users/— create a user fromCreateUserDto(guarded with@Authorized()).PUT /api/v1/users/:id— update a user fromUpdateUserDto.DELETE /api/v1/users/:id— delete a user; the service intentionally throws afterward to demonstrate transaction rollback hooks.
GET /api/v1/paging/paginated— return a page of users fromPagingUserRepository.findPaginated(...)using@QueryParams() PagingRequest.GET /api/v1/paging/cursor— return a cursor page of users using@QueryParams() CursorRequest.GET /api/v1/paging/paginated/filter— paginated users filtered toemail = "example3@email.com".GET /api/v1/paging/cursor/filter— cursor-paginated users filtered toemail = "example3@email.com".
This sample uses @nodeboot/authorization, but the implementation is intentionally demo-only and does not use JWTs, sessions, or a database-backed identity provider.
LoggedInUserResolverimplementsCurrentUserChecker, logs the check, and returns a hard-coded current user object:id: 1username: "exampleUser"
DefaultAuthorizationResolverimplementsAuthorizationChecker, logs the check, creates a mock user with rolesUSERandADMIN, and authorizes:- any request when
@Authorized()is present without role arguments - any request whose required role matches one of the mock roles
- any request when
In this sample, @Authorized() is applied to POST /api/v1/users/. For production-ready patterns (including JWT/Firebase-style resolvers and richer role checks), see the Authorization README.
LoggingMiddleware— a global@Middleware({ type: "before" })example that logs each incoming request before controller execution.ErrorMiddleware— a custom@ErrorHandler()that logs[METHOD] path, resolves the HTTP status fromHttpError, and returns a JSON response shaped like:
{
"message": "...",
"statusCode": 400
}The sample configuration sets app.defaultErrorHandler: false, which makes this custom error-handling path especially relevant.
The persistence layer is built on @nodeboot/starter-persistence, TypeORM, and local SQLite.
Userentity fields:id,email,password, and nullablenameCustomNamingStrategyprefixes table names withnb-, so the user table becomesnb-user- Migrations:
1701774002463-migration.tscreatesnb-userwithid,email, andpassword1701786331338-migration.tsadds thenamecolumn
DatasourceOverridesConfigurationalso declares SQLite datasource settings in code (better-sqlite3,express-sample.db,synchronize: false,migrationsRun: true)UserRepositorydemonstrates a custom query-builder repository method:findByQueryIn()PagingUserRepositoryextendsPagingAndSortingRepository<User>for page/cursor examplesusers.init.tsseeds four demo users when the table is emptyUserServicedemonstrates@Transactional()methods plusrunOnTransactionCommit(...)andrunOnTransactionRollback(...)- Entity subscribers:
GlobalEntityEventListenerlogs load, insert, update, remove, recover, and transaction lifecycle eventsUserEntityEventListenerlistens specifically toUserinserts and callsGreetingService.sayHello(...)
Because persistence.migrationsRun is enabled, the sample applies migrations automatically on startup.
SchedulersComponent demonstrates cron-style scheduled work with @nodeboot/starter-scheduler:
*/1 * * * *—fastTask()every minute*/5 * * * *—cleanUp()every five minutes0 9 * * *—morningRoutine()every day at 9:00 AM
MicroserviceHttpClient demonstrates @nodeboot/starter-http integration:
- base URL:
https://jsonplaceholder.typicode.com - timeout:
5000 - HTTP logging: enabled
UserService.findExternalUsers() uses this client to call GET /users on the external service and return the remote payload through GET /api/v1/users/external/.
| Script | Purpose |
|---|---|
pnpm start |
Clean, build, and run dist/server.js. |
pnpm start:prod |
Build and run dist/server.js with NODE_ENV=production. |
pnpm dev |
Run the nodemon-based development loop. |
pnpm aot-script |
Run the AOT cycle-detector script. |
pnpm model-gen |
Run the AOT model-schema generator script. |
pnpm nodeboot:update |
Update @nodeboot/* dependencies to latest. |
pnpm build |
Compile TypeScript with tsconfig.build.json. |
pnpm postbuild |
Generate AOT artifacts after build. |
pnpm clean:build |
Remove dist/. |
pnpm lint |
Run ESLint. |
pnpm lint:fix |
Run ESLint with --fix. |
pnpm format |
Check formatting with Prettier. |
pnpm format:fix |
Rewrite formatting with Prettier. |
pnpm pretest |
Clean and build before tests. |
pnpm test |
Run the Node test suite with ts-node/register. |
pnpm test:coverage |
Run tests with experimental coverage output. |
pnpm tsc |
Run tsc. |
pnpm rebuild:sqlite |
Rebuild the native better-sqlite3 dependency. |
pnpm create:migration |
Create a new TypeORM migration under src/persistence/migrations/. |
MIT