This sample boots Node-Boot with NodeBoot.run(HttpServer), using @nodeboot/http-server: the zero-framework-dependency server adapter built directly on Node's native http module and the find-my-way router.
It shows that a Node-Boot application can keep the same decorator-driven programming model without Express, Fastify, or Koa while still using persistence, authorization, scheduling, HTTP clients, OpenAPI/Swagger, validation, and actuator endpoints.
The application starts on port 3000, serves its API under /api, and defines versioned controllers under /v1/....
- Native HTTP bootstrapping with
@nodeboot/http-server - Authorization and current-user resolvers with
@nodeboot/authorization - SQLite persistence, repositories, transactions, migrations, and entity listeners with
@nodeboot/starter-persistence - Cron-style scheduled jobs with
@nodeboot/starter-scheduler - Outbound HTTP clients with
@nodeboot/starter-http - OpenAPI generation and Swagger UI with
@nodeboot/starter-openapi - DTO/model validation with
@nodeboot/starter-validation - Operational endpoints with
@nodeboot/starter-actuator
FactsServiceApp combines these decorators to enable the sample's features:
@EnableDI(Container)— enables dependency injection with TypeDI.@EnableOpenApi()— generates the OpenAPI spec.@EnableSwaggerUI()— serves the interactive Swagger UI.@EnableAuthorization(LoggedInUserResolver, DefaultAuthorizationResolver)— wires the demo current-user and authorization checkers.@EnableActuator()— exposes/actuator/*operational endpoints.@EnableRepositories()— enables repository discovery for TypeORM-backed persistence.@EnableScheduling()— enables cron-based scheduled methods.@EnableHttpClients()— enables decorated outbound HTTP clients.@EnableValidations()— enables request DTO validation.@EnableComponentScan()— enables AOT/component scanning.@NodeBootApplication()— marks the class as the application entry point.
- Node.js
pnpm- Monorepo dependencies installed from the repository root (
pnpm install) - A runtime able to build
better-sqlite3if needed
From the repository root:
pnpm install
pnpm --filter @nodeboot/native-http-sample run startUseful alternatives:
pnpm --filter @nodeboot/native-http-sample run dev
pnpm --filter @nodeboot/native-http-sample run start:prodOnce running:
- API base URL:
http://localhost:3000/api - Swagger UI:
http://localhost:3000/api-docs/ - OpenAPI JSON:
http://localhost:3000/api-docs/swagger.json - Actuator root:
http://localhost:3000/actuator
app-config.yaml defines these committed settings:
app.port: 3000api.routePrefix: /api- validation options under
api.validations - CORS options under
server.cors - multipart-related limits under
server.multipart - OpenAPI metadata under
openapi - SQLite persistence under
persistenceusingbetter-sqlite3
No secrets are present in the committed sample config.
AppConfigPropertiesbinds theappsection fromapp-config.yamlClassTransformConfigurationsets class-transform options and disables the class transformer via@EnableClassTransformer({enabled: false})ServerConfigurationexposesHttpServerConfigsfrom config, including cookie/cors/session/multipart/template option slots
src/
├── app.ts # Application class; boots Node-Boot with HttpServer
├── server.ts # Process entry point
├── auth/
│ ├── DefaultAuthorizationResolver.ts
│ └── LoggedInUserResolver.ts
├── clients/
│ └── MicroserviceHttpClient.ts # Outbound HTTP client for jsonplaceholder.typicode.com
├── config/
│ ├── AppConfigProperties.ts
│ ├── ClassTransformConfiguration.ts
│ └── ServerConfiguration.ts
├── controllers/
│ ├── hello.controller.ts
│ ├── paging.controller.ts
│ └── users.controller.ts
├── exceptions/
│ └── httpException.ts
├── interfaces/
│ └── users.interface.ts
├── middlewares/
│ ├── CustomErrorHandler.ts
│ └── LoggingMiddleware.ts
├── models/
│ ├── CreateUserDto.ts
│ ├── UpdateUserDto.ts
│ ├── UserModel.ts
│ └── index.ts
├── persistence/
│ ├── entities/User.ts
│ ├── repositories/
│ ├── listeners/
│ ├── migrations/
│ ├── CustomNamingStrategy.ts
│ ├── DatasourceOverridesConfiguration.ts
│ └── users.init.ts
└── services/
├── greeting.service.ts
├── schedulers.component.ts
└── users.service.ts
Base prefix from configuration: /api
Controller decorator: @Controller("/hello", "v1")
GET /api/v1/hello/— returns"Hello, World!"
Controller decorator: @Controller("/paging", "v1")
GET /api/v1/paging/paginated— returns aPage<UserModel>usingPagingRequestquery paramsGET /api/v1/paging/cursor— returns aCursorPage<UserModel>usingCursorRequestquery paramsGET /api/v1/paging/paginated/filter— paginated results filtered toemail = "example3@email.com"GET /api/v1/paging/cursor/filter— cursor-paginated results filtered toemail = "example3@email.com"
Controller decorator: @Controller("/users", "v1")
GET /api/v1/users/— lists persisted usersGET /api/v1/users/external/— fetches users fromhttps://jsonplaceholder.typicode.com/usersGET /api/v1/users/query/— returns users from a custom repository query (id IN (1, 2))GET /api/v1/users/:id— fetches one user by idPOST /api/v1/users/— creates a user, returns201, and is decorated with@Authorized()PUT /api/v1/users/:id— updates a user usingUpdateUserDtoDELETE /api/v1/users/:id— deletes a user, then intentionally throws to demonstrate transaction rollback behavior
CreateUserDtoemail:@IsEmail()name:@IsString()password:@IsString(),@IsNotEmpty(),@MinLength(9),@MaxLength(32)
UpdateUserDtopassword:@IsString(),@IsNotEmpty(),@MinLength(9),@MaxLength(32)
UserModel- OpenAPI model with
id,email, and optionalname
- OpenAPI model with
This sample uses @EnableAuthorization with two demo resolvers:
LoggedInUserResolverimplementsCurrentUserChecker<IncomingMessage, ServerResponse>DefaultAuthorizationResolverimplementsAuthorizationChecker<IncomingMessage, ServerResponse>
Both are explicitly typed against Node's native IncomingMessage and ServerResponse, matching the native HTTP adapter.
Behavior shown here:
LoggedInUserResolverlogs and returns a hard-coded current user objectDefaultAuthorizationResolverlogs and authorizes a hard-coded user with rolesUSERandADMINPOST /api/v1/users/is the only route protected with@Authorized()in this sample
For adapter details, see the authorization section in the @nodeboot/http-server README. That README also documents current native-adapter limitations relevant here: session-based decorators and multipart/file-upload decorators are not implemented.
LoggingMiddleware- Decorated with
@Middleware({type: "before"}) - Runs before requests and logs
Logging Middleware: Incoming request
- Decorated with
CustomErrorHandler- Decorated with
@ErrorHandler() - Implements
ErrorHandlerInterface<HttpError, IncomingMessage, ServerResponse> - Writes a JSON error response with
messageandstatusCode
- Decorated with
The sample config sets app.defaultErrorHandler: false, so the custom handler is intended to replace the default global handler.
Persistence is enabled with @EnableRepositories() and uses TypeORM plus better-sqlite3.
Userentity withid,email,password, and nullablenameUserRepositorywith a customfindByQueryIn()query builder examplePagingUserRepositoryextendingPagingAndSortingRepository<User>CustomNamingStrategythat prefixes table names withnb-DatasourceOverridesConfigurationshowing programmatic datasource configurationusers.init.tsseeding four users when the table is empty- two migrations:
1701774002463-migration.tscreates tablenb-user1701786331338-migration.tsadds nullablename
UserService demonstrates transactional helpers:
@Transactional()on create, update, and delete methodsrunOnTransactionCommit(...)during user creationrunOnTransactionRollback(...)during user deletion
Entity listeners demonstrate lifecycle hooks:
UserEntityEventListenerlogs before/after insertingUserand callsGreetingService.sayHello(...)GlobalEntityEventListenerlogs load, insert, update, remove, soft-remove, recover, and transaction events globally
In app-config.yaml, persistence is configured with:
type: better-sqlite3synchronize: falsemigrationsRun: true- database file
sample-database.db
The sample also includes DatasourceOverridesConfiguration, which hardcodes a better-sqlite3 datasource as an additional programmatic configuration example.
SchedulersComponent contains three scheduled methods enabled by @EnableScheduling():
@Scheduler("*/1 * * * *")— every minute@Scheduler("*/5 * * * *")— every five minutes@Scheduler("0 9 * * *")— every day at 9 AM
Each logs when it runs.
MicroserviceHttpClient extends HttpClientStub and is decorated with:
@HttpClient({ baseURL: "https://jsonplaceholder.typicode.com", timeout: 5000, httpLogging: true })
UserService.findExternalUsers() uses it to call GET /users on that external API.
From package.json:
pnpm run start— clean, build, then rundist/server.jspnpm run start:prod— build and run in production modepnpm run dev— run withnodemonin development modepnpm run nodeboot:update— update@nodeboot/*packagespnpm run build— compile TypeScript withtsconfig.build.jsonpnpm run postbuild— run Node-Boot AOT generation (npx @nodeboot/aot node-boot-aot)pnpm run clean:build— removedist/pnpm run lint— run ESLintpnpm run lint:fix— run ESLint with--fixpnpm run format— check Prettier formattingpnpm run format:fix— apply Prettier formattingpnpm run test— run tests withnode --testpnpm run tsc— run TypeScript compilerpnpm run rebuild:sqlite— rebuildbetter-sqlite3pnpm run create:migration— create a TypeORM migration undersrc/persistence/migrations/
MIT