Overview
Start a NestJS application with Express adapter. Includes Swagger, versioning, CORS, Helmet, and request logging.
Features
- Express adapter (familiar ecosystem)
- Swagger API documentation
- API versioning support
- Class-based modular setup
- Request/response logging
Installation
npx hanma add nest-express-server --framework nest
Dependencies
@nestjs/core, @nestjs/common, @nestjs/platform-express, @nestjs/swagger, helmet
Code
import { ConfigService } from "@nestjs/config";
import { NestFactory } from "@nestjs/core";
import {
DynamicModule,
ForwardReference,
Type,
VersioningType,
Logger,
ValidationPipe,
} from "@nestjs/common";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import { NestExpressApplication } from "@nestjs/platform-express";
import helmet from "helmet";
import type { Request, Response, NextFunction } from "express";
import type { ServerOptions } from "./server.interface";
type ModuleType = Type<any> | DynamicModule | ForwardReference;
export class HttpServer {
private static logger = new Logger("HTTP");
private static app: NestExpressApplication;
/**
* Bootstrap and start the NestJS application
*/
static async create(module: ModuleType, options: ServerOptions = {}) {
const app = await NestFactory.create<NestExpressApplication>(module, {
logger: ["log", "error", "warn", "debug", "verbose"],
});
this.app = app;
const config = app.get(ConfigService);
const isDev = config.get("NODE_ENV") !== "production";
// Apply defaults
const opts: Required<ServerOptions> = {
port: options.port ?? config.get<number>("PORT", 3000),
enableVersioning: options.enableVersioning ?? false,
defaultVersion: options.defaultVersion ?? "1",
enableApiDocumentation: options.enableApiDocumentation ?? isDev,
swaggerPath: options.swaggerPath ?? "api/docs",
enableServerLogs: options.enableServerLogs ?? true,
globalPrefix: options.globalPrefix ?? "api",
};
// Setup all middleware and configurations
this.setupGlobalPrefix(opts);
this.setupVersioning(opts);
this.setupCors(config);
this.setupHelmet();
this.setupValidation();
this.setupSwagger(config, opts);
this.setupRequestLogging(opts);
this.setupGracefulShutdown();
// Start server
await app.listen(opts.port);
this.logger.log(`Server running on: http://localhost:${opts.port}/${opts.globalPrefix}`);
if (opts.enableApiDocumentation) {
this.logger.log(`API docs: http://localhost:${opts.port}/${opts.swaggerPath}`);
}
return app;
}
private static setupGlobalPrefix(opts: Required<ServerOptions>) {
this.app.setGlobalPrefix(opts.globalPrefix);
}
private static setupVersioning(opts: Required<ServerOptions>) {
if (!opts.enableVersioning) return;
this.app.enableVersioning({
type: VersioningType.URI,
prefix: "v",
defaultVersion: opts.defaultVersion,
});
this.logger.log(`API versioning enabled (default: v${opts.defaultVersion})`);
}
private static setupCors(config: ConfigService) {
const allowedOrigins = config
.get<string>("CORS_ORIGINS", "*")
.split(",")
.map((origin) => origin.trim())
.filter(Boolean);
const allowedMethods = config
.get<string>("CORS_METHODS", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
.split(",")
.filter(Boolean);
this.app.enableCors({
origin: (origin, callback) => {
// Allow requests with no origin (like mobile apps or curl)
if (!origin || allowedOrigins.includes("*") || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
this.logger.warn(`CORS blocked: ${origin}`);
callback(new Error("Not allowed by CORS"), false);
}
},
methods: allowedMethods,
credentials: true,
});
}
private static setupHelmet() {
this.app.use(
helmet({
contentSecurityPolicy: process.env.NODE_ENV === "production",
})
);
}
private static setupValidation() {
this.app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: {
enableImplicitConversion: true,
},
})
);
}
private static setupSwagger(config: ConfigService, opts: Required<ServerOptions>) {
if (!opts.enableApiDocumentation) return;
const appName = process.env.npm_package_name || config.get<string>("APP_NAME", "NestJS API");
const appVersion = process.env.npm_package_version || config.get<string>("APP_VERSION", "1.0.0");
const appDescription = process.env.npm_package_description || config.get<string>("APP_DESCRIPTION", "API documentation");
const documentConfig = new DocumentBuilder()
.setTitle(appName)
.setDescription(appDescription)
.setVersion(appVersion)
.addBearerAuth()
.addTag("API")
.build();
const document = SwaggerModule.createDocument(this.app, documentConfig);
SwaggerModule.setup(opts.swaggerPath, this.app, document, {
swaggerOptions: {
persistAuthorization: true,
docExpansion: "none",
},
});
}
private static setupRequestLogging(opts: Required<ServerOptions>) {
if (!opts.enableServerLogs) return;
this.app.use((req: Request, res: Response, next: NextFunction) => {
const startTime = Date.now();
res.on("finish", () => {
const duration = Date.now() - startTime;
const { method, originalUrl } = req;
const { statusCode } = res;
const logFn =
statusCode >= 500
? this.logger.error.bind(this.logger)
: statusCode >= 400
? this.logger.warn.bind(this.logger)
: this.logger.log.bind(this.logger);
logFn(`${method} ${originalUrl} ${statusCode} - ${duration}ms`);
});
next();
});
}
private static setupGracefulShutdown() {
this.app.enableShutdownHooks();
process.on("SIGTERM", async () => {
this.logger.log("SIGTERM signal received, closing gracefully...");
await this.app.close();
});
process.on("SIGINT", async () => {
this.logger.log("SIGINT signal received, closing gracefully...");
await this.app.close();
});
}
/**
* Get the application instance
*/
static getApp() {
return this.app;
}
}
/* USAGE in main.ts:
import { HttpServer } from "./server.setup";
import { AppModule } from "./app.module";
HttpServer.create(AppModule, {
enableVersioning: false,
enableApiDocumentation: true,
enableServerLogs: true,
}).catch((err) => {
console.error("Failed to start application:", err);
process.exit(1);
});
*/
Usage
HttpServer.create(AppModule, {\n enableVersioning: true,\n enableApiDocumentation: true,\n});
Dependencies
@nestjs/core@nestjs/common@nestjs/platform-express@nestjs/swaggerhelmet
Frequently Asked Questions
How do I install NestJS Express Server?
Run the following command:
npx hanma add nest-express-server --framework nestWhat dependencies are required?
This snippet requires: @nestjs/core, @nestjs/common, @nestjs/platform-express, @nestjs/swagger, helmet. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to
src/main.ts.Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.