// Simple NestJS controller example
import { Controller, Get } from '@nestjs/common';
@Controller('hello')
export class HelloController {
@Get()
getHello(): string {
return 'Hello from NestJS!';
}
}
// Example of dependency injection
@Injectable()
export class CatsService {
getCats() {
return ['cat1', 'cat2'];
}
}
// Express route
app.get('/cats', (req, res) => {
res.send(['cat1', 'cat2']);
});
// NestJS route (as above)
// Example Module
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
npm i -g @nestjs/cli
nest new project-name
cd project-name
npm run start
npm install -g @nestjs/cli
nest new my-nest-app
my-nest-app/
├── src/
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── package.json
└── nest-cli.json
npm run start
// or for live reload
npm run start:dev
// Install config package
npm install @nestjs/config
// In app.module.ts
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule.forRoot()],
})
export class AppModule {}
import { Module } from '@nestjs/common';
@Module({
controllers: [...],
providers: [...],
imports: [...],
exports: [...],
})
export class FeatureModule {}
nest generate module cats
// or
nest g mo cats
@Module({
controllers: [CatsController],
providers: [CatsService],
imports: [],
exports: [CatsService],
})
export class CatsModule {}
@Module({
imports: [CatsModule],
})
export class AppModule {}
import { Global, Module } from '@nestjs/common';
@Global()
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll() {
return 'This action returns all cats';
}
}
@Controller('cats')
export class CatsController {
@Get()
findAll() { /* ... */ }
@Post()
create() { /* ... */ }
@Put(':id')
update(@Param('id') id: string) { /* ... */ }
@Delete(':id')
remove(@Param('id') id: string) { /* ... */ }
}
@Post()
create(@Body() createCatDto) {
return `Create cat with name ${createCatDto.name}`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `Cat #${id}`;
}
@Get()
findByBreed(@Query('breed') breed: string) {
return `Cats of breed ${breed}`;
}
import { Injectable } from '@nestjs/common';
@Injectable()
export class CatsService {
private readonly cats = [];
findAll() {
return this.cats;
}
}
import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
findAll() {
return this.catsService.findAll();
}
}
{
provide: 'CUSTOM_TOKEN',
useClass: CustomService,
}
{
provide: ConfigService,
useFactory: () => {
return new ConfigService(process.env.CONFIG);
},
}
@Injectable({ scope: Scope.REQUEST })
export class ScopedService { }
// Example: middleware logs each request
function logger(req, res, next) {
console.log(`${req.method} ${req.url}`);
next();
}
function authMiddleware(req, res, next) {
if (!req.headers.authorization) {
res.status(401).send('Unauthorized');
} else {
next();
}
}
// Global
app.use(authMiddleware);
// Specific route
app.get('/profile', authMiddleware, (req, res) => {
res.send('User Profile');
});
const bodyParser = require('body-parser');
app.use(bodyParser.json()); // parses JSON bodies
throw new NotFoundException('Resource not found');
class CustomException extends HttpException {
constructor() {
super('Custom error occurred', 400);
}
}
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
response.status(500).json({ message: 'Internal server error' });
}
}
@Catch(NotFoundException)
export class NotFoundFilter implements ExceptionFilter {
catch(exception: NotFoundException, host: ArgumentsHost) {
// custom logic here
}
}
@Query()
getUser(@Param('id', ParseIntPipe) id: number) {
return this.userService.findById(id);
}
@UsePipes(new ValidationPipe())
createUser(@Body() createUserDto: CreateUserDto) {
// validated dto here
}
@Injectable()
export class TrimPipe implements PipeTransform {
transform(value: any) {
if (typeof value === 'string') {
return value.trim();
}
return value;
}
}
// Global
app.useGlobalPipes(new ValidationPipe());
// Controller
@UsePipes(new ValidationPipe())
@Controller('users')
export class UsersController {}
// Parameter
getUser(@Param('id', ParseIntPipe) id: number) {}
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return request.headers.authorization === 'valid-token';
}
}
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly roles: string[]) {}
canActivate(context: ExecutionContext): boolean {
const user = context.switchToHttp().getRequest().user;
return this.roles.includes(user.role);
}
}
@Injectable()
export class CustomGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
// Custom logic here
return true; // or false
}
}
import { Controller, Get, UseGuards } from '@nestjs/common';
@Controller('cats')
@UseGuards(AuthGuard)
export class CatsController {
@Get()
findAll() {
return 'This route is protected by AuthGuard';
}
}
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
console.log('Before handler execution');
const now = Date.now();
return next
.handle()
.pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)));
}
}
// Example: Response mapping interceptor
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
return next.handle().pipe(
map(data => ({ data, timestamp: new Date().toISOString() })),
);
}
}
import { Controller, Get, UseInterceptors } from '@nestjs/common';
@Controller('cats')
@UseInterceptors(LoggingInterceptor)
export class CatsController {
@Get()
findAll() {
return ['cat1', 'cat2'];
}
}
@Injectable()
export class CustomInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
// Custom pre-processing
return next.handle().pipe(
// Custom post-processing
);
}
}
import { IsString, IsEmail } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
}
export class UpdateUserDto {
@IsString()
name?: string;
@IsEmail()
email?: string;
}
import { ValidationPipe } from '@nestjs/common';
app.useGlobalPipes(new ValidationPipe());
// Example error response
{
"statusCode": 400,
"message": [
"name must be a string",
"email must be an email"
],
"error": "Bad Request"
}
// Install
npm install @nestjs/config
// In app.module.ts
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule.forRoot()],
})
export class AppModule {}
// .env file
DATABASE_HOST=localhost
DATABASE_PORT=5432
// Usage in service
import { ConfigService } from '@nestjs/config';
constructor(private configService: ConfigService) {}
const dbHost = this.configService.get('DATABASE_HOST');
interface EnvConfig {
DATABASE_HOST: string;
DATABASE_PORT: number;
}
const config = () => ({
DATABASE_HOST: process.env.DATABASE_HOST,
DATABASE_PORT: parseInt(process.env.DATABASE_PORT, 10),
});
ConfigModule.forRoot({
envFilePath: `.env.${process.env.NODE_ENV || 'development'}`,
});
import { Logger } from '@nestjs/common';
const logger = new Logger('MyApp');
logger.log('This is a log message');
logger.error('This is an error');
logger.warn('This is a warning');
import { Logger } from '@nestjs/common';
export class MyLogger extends Logger {
log(message: string) {
// custom behavior
super.log(message);
}
}
// Example with Winston integration
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
@Module({
imports: [
WinstonModule.forRoot({
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'combined.log' }),
],
}),
],
})
export class AppModule {}
// Install
npm install --save @nestjs/typeorm typeorm pg
// Setup in app.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'user',
password: 'pass',
database: 'mydb',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
],
})
export class AppModule {}
// Install
npm install --save @nestjs/sequelize sequelize sequelize-typescript pg
// Setup in app.module.ts
import { SequelizeModule } from '@nestjs/sequelize';
@Module({
imports: [
SequelizeModule.forRoot({
dialect: 'postgres',
host: 'localhost',
port: 5432,
username: 'user',
password: 'pass',
database: 'mydb',
models: [User],
autoLoadModels: true,
}),
],
})
export class AppModule {}
// Install
npm install --save @nestjs/mongoose mongoose
// Setup
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/nest'),
],
})
export class AppModule {}
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private userRepository: Repository,
) {}
findAll() {
return this.userRepository.find();
}
}
// TypeORM entity example
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}
const jwt = require('jsonwebtoken');
const token = jwt.sign({ userId: 123 }, 'your-secret-key', { expiresIn: '1h' });
const passport = require('passport');
const JwtStrategy = require('passport-jwt').Strategy;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
User.findById(jwt_payload.userId)
.then(user => done(null, user))
.catch(err => done(err, false));
}));
// Sessions example with express-session
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true }));
app.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
res.send('Protected profile page');
});
// Issue refresh token alongside access token
const refreshToken = jwt.sign({ userId: 123 }, 'refresh-secret', { expiresIn: '7d' });
function checkRole(role) {
return (req, res, next) => {
if (req.user.role === role) {
next();
} else {
res.status(403).send('Forbidden');
}
};
}
// Example policy
const canEditPost = (user, post) => user.id === post.authorId || user.role === 'admin';
app.get('/admin', passport.authenticate('jwt', { session: false }), checkRole('admin'), (req, res) => {
res.send('Welcome Admin');
});
@WebSocketGateway()
export class EventsGateway {
@WebSocketServer()
server;
}
@SubscribeMessage('message')
handleMessage(client: Socket, payload: any) {
this.server.emit('message', payload);
}
this.server.emit('eventName', data); // broadcast to all connected clients
import { Server } from 'socket.io';
const io = new Server(server);
io.on('connection', socket => {
socket.on('chat', msg => {
io.emit('chat', msg);
});
});
npm install graphql @nestjs/graphql apollo-server-express
// Code-first example (NestJS):
@ObjectType()
class User {
@Field()
name: string;
}
@Resolver()
export class UserResolver {
@Query(() => String)
hello() {
return 'Hello GraphQL';
}
}
@Subscription(() => Message)
messageAdded() {
// logic for realtime message updates
}
// URI versioning example
GET /api/v1/users
// Query params example
GET /users?limit=10&offset=20
{
"users": [...],
"links": {
"next": "/api/v1/users?offset=20&limit=10"
}
}
HTTP/1.1 404 Not Found
{
"error": "User not found"
}
test('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
// Example testing a service method
describe('UserService', () => {
it('should return a user by ID', () => {
// test code here
});
});
// Example with Jest and Supertest
describe('AppController (e2e)', () => {
it('/GET users', () => {
return request(app.getHttpServer())
.get('/users')
.expect(200)
.expect(response => {
expect(response.body).toBeInstanceOf(Array);
});
});
});
const mockUserService = {
findUser: jest.fn().mockReturnValue({ id: 1, name: 'Test User' }),
};
import { Injectable } from '@nestjs/common';
import { Cron, Interval, Timeout } from '@nestjs/schedule';
@Injectable()
export class TasksService {
@Cron('45 * * * * *')
handleCron() {
console.log('Called every minute at second 45');
}
@Interval(10000)
handleInterval() {
console.log('Called every 10 seconds');
}
@Timeout(5000)
handleTimeout() {
console.log('Called once after 5 seconds');
}
}
// Cron example: every day at midnight
@Cron('0 0 0 * * *')
handleDailyTask() {
// Do daily task
}
// Interval example: every 5 minutes
@Interval(300000)
handleRepeatTask() {
// Do repeated task
}
@Timeout(60000)
handleDelayedTask() {
console.log('Runs once after 1 minute');
}
import { SchedulerRegistry } from '@nestjs/schedule';
constructor(private schedulerRegistry: SchedulerRegistry) {}
cancelJob(name: string) {
const job = this.schedulerRegistry.getCronJob(name);
job.stop();
}
import { BullModule } from '@nestjs/bull';
@Module({
imports: [
BullModule.forRoot({
redis: {
host: 'localhost',
port: 6379,
},
}),
BullModule.registerQueue({
name: 'email',
}),
],
})
export class AppModule {}
// Producer - add job
await this.emailQueue.add({ to: 'user@example.com', subject: 'Hello!' });
// Consumer - process job
@Processor('email')
export class EmailProcessor {
@Process()
async handleEmailJob(job: Job) {
console.log('Sending email to', job.data.to);
// send email logic
}
}
// Add job with delay and retries
await this.emailQueue.add(
{ to: 'user@example.com' },
{
delay: 60000, // wait 60 seconds
attempts: 3, // retry 3 times if failed
},
);
this.emailQueue.on('completed', (job) => {
console.log(`Job ${job.id} completed!`);
});
this.emailQueue.on('failed', (job, err) => {
console.log(`Job ${job.id} failed with error ${err.message}`);
});
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
@Controller('upload')
export class UploadController {
@Post()
@UseInterceptors(FileInterceptor('file'))
uploadFile(@UploadedFile() file: Express.Multer.File) {
console.log(file);
return { message: 'File uploaded successfully!' };
}
}
// HTML form example
<form method="POST" enctype="multipart/form-data" action="/upload">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>
@Post('stream')
@UseInterceptors(FileInterceptor('file'))
uploadStream(@UploadedFile() file: Express.Multer.File) {
const stream = file.stream;
// Process stream data chunk by chunk
}
@UseInterceptors(FileInterceptor('file', {
limits: { fileSize: 2 * 1024 * 1024 }, // 2MB max
fileFilter: (req, file, cb) => {
if (!file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) {
return cb(new Error('Only images are allowed!'), false);
}
cb(null, true);
}
}))
import { CacheModule, Module } from '@nestjs/common';
@Module({
imports: [CacheModule.register()],
})
export class AppModule {}
import { Injectable, Cacheable } from '@nestjs/common';
@Injectable()
export class CatsService {
@Cacheable()
getCats() {
// This result will be cached in memory
}
}
CacheModule.register({
store: require('cache-manager-redis-store'),
host: 'localhost',
port: 6379,
});
import { CacheInterceptor, UseInterceptors, Controller, Get } from '@nestjs/common';
@Controller('cats')
@UseInterceptors(CacheInterceptor)
export class CatsController {
@Get()
findAll() {
// Response will be cached automatically
return ['cat1', 'cat2'];
}
}
import * as helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(helmet());
await app.listen(3000);
}
bootstrap();
// Example: Using csurf middleware for CSRF protection
import * as csurf from 'csurf';
app.use(csurf());
import { ThrottlerModule } from '@nestjs/throttler';
@Module({
imports: [
ThrottlerModule.forRoot({
ttl: 60,
limit: 10,
}),
],
})
export class AppModule {}
@Injectable()
export class ApiKeyGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
return request.headers['x-api-key'] === 'my-secret-key';
}
}
npm install nestjs-i18n
import { I18nModule } from 'nestjs-i18n';
@Module({
imports: [
I18nModule.forRoot({
fallbackLanguage: 'en',
loaderOptions: {
path: path.join(__dirname, '/i18n/'),
watch: true,
},
}),
],
})
export class AppModule {}
{
"HELLO": "Hello",
"WELCOME": "Welcome to our app"
}
@Get()
async hello(@I18nLang() lang: string, @I18n() i18n: I18nService) {
return i18n.t('HELLO', { lang });
}
// Install
npm install --save @nestjs/swagger swagger-ui-express
// main.ts setup
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
const config = new DocumentBuilder()
.setTitle('My API')
.setDescription('API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
@ApiTags('cats')
@Controller('cats')
export class CatsController {
@Get()
@ApiOperation({ summary: 'Get all cats' })
@ApiResponse({ status: 200, description: 'List of cats.' })
findAll() {
return [];
}
}
import { ApiProperty } from '@nestjs/swagger';
export class CreateCatDto {
@ApiProperty({ description: 'Name of the cat' })
name: string;
@ApiProperty({ description: 'Age of the cat', minimum: 0 })
age: number;
}
// After setup, visit
http://localhost:3000/api
npm run build
node dist/main.js
# Dockerfile example
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY dist ./dist
CMD ["node", "dist/main.js"]
// Example GitHub Actions snippet
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: '18'
- run: npm install
- run: npm run build
- run: npm test
- run: npm run deploy
ConfigModule.forRoot({
envFilePath: `.env.${process.env.NODE_ENV}`,
});
import { Transport, ClientProxyFactory } from '@nestjs/microservices';
const client = ClientProxyFactory.create({
transport: Transport.TCP,
options: { host: 'localhost', port: 4000 },
});
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
@Controller()
export class MathController {
@MessagePattern({ cmd: 'sum' })
accumulate(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
}
client.send({ cmd: 'sum' }, [1, 2, 3]).subscribe(result => {
console.log('Sum is', result);
});
// Create monorepo
nest new project-name --monorepo
// Generate library
nest generate library common
// Use shared code
import { SharedService } from '@project/common';
// Run specific app
npm run start:app1
// Build specific app
npm run build:app2
@Module({})
export class DynamicModule {
static forRoot(options: any): DynamicModule {
return {
module: DynamicModule,
providers: [{ provide: 'CONFIG_OPTIONS', useValue: options }],
exports: ['CONFIG_OPTIONS'],
};
}
}
@Injectable()
export class AppService implements OnModuleInit, OnModuleDestroy {
onModuleInit() {
console.log('Module initialized');
}
onModuleDestroy() {
console.log('Module destroyed');
}
}
export function Roles(...roles: string[]) {
return SetMetadata('roles', roles);
}
@Roles('admin')
@Controller('admin')
export class AdminController {}
import 'reflect-metadata';
Reflect.defineMetadata('role', 'admin', AdminController);
const role = Reflect.getMetadata('role', AdminController);
console.log(role); // admin
@Module({
imports: [LazyModule],
})
export class AppModule {}
@NgModule({
imports: [RouterModule.forChild([{ path: '', component: LazyComponent }])],
})
export class LazyModule {}
@Injectable()
export class CacheService {
private cache = new Map();
get(key: string) {
return this.cache.get(key);
}
set(key: string, value: any) {
this.cache.set(key, value);
}
}
const users = await userRepository.find({
where: { isActive: true },
relations: ['profile'],
});
// Example with New Relic or similar tools
app.use(newrelicMiddleware());
// Example folder structure by domain
src/
├── users/
│ ├── domain/
│ │ ├── entities/
│ │ │ └── user.entity.ts
│ │ ├── services/
│ │ │ └── user.service.ts
│ ├── application/
│ │ └── user.use-case.ts
│ ├── infrastructure/
│ │ └── user.repository.ts
│ └── users.module.ts
// Example of layered approach
@Controller('users')
export class UserController {
constructor(private readonly userUseCase: UserUseCase) {}
@Get(':id')
getUser(@Param('id') id: string) {
return this.userUseCase.execute(id);
}
}
// Application layer
export class UserUseCase {
constructor(private readonly userService: UserService) {}
execute(id: string) {
return this.userService.findById(id);
}
}
src/
├── users/
│ ├── controllers/
│ │ └── user.controller.ts
│ ├── services/
│ │ └── user.service.ts
│ ├── repositories/
│ │ └── user.repository.ts
│ ├── dtos/
│ │ └── create-user.dto.ts
│ └── entities/
│ └── user.entity.ts
// Example shared module
@Module({
providers: [LoggerService],
exports: [LoggerService],
})
export class SharedModule {}