ในโลกของ Backend Development ด้วย Node.js เรามี Framework มากมายให้เลือกใช้ ตั้งแต่ Express ที่เรียบง่ายไปจนถึง Fastify ที่เน้นประสิทธิภาพ แต่เมื่อโปรเจกต์เติบโตขึ้นจนกลายเป็นระบบขนาดใหญ่ที่มีทีมพัฒนาหลายสิบคน ปัญหาเรื่องโครงสร้าง Code ที่ไม่เป็นระเบียบ การจัดการ Dependency ที่ซับซ้อน และการบำรุงรักษาที่ยากลำบากก็ตามมา NestJS คือ Framework ที่ถูกสร้างมาเพื่อแก้ปัญหาเหล่านี้โดยเฉพาะ
บทความนี้จะพาคุณเจาะลึกทุกแง่มุมของ NestJS ตั้งแต่แนวคิดพื้นฐาน โครงสร้างโปรเจกต์ ไปจนถึงการสร้าง Microservices และ GraphQL API พร้อมตัวอย่าง Code ที่ใช้ได้จริงในปี 2026
NestJS คืออะไร?
NestJS คือ Progressive Node.js Framework สำหรับสร้าง Server-side Application ที่มีประสิทธิภาพสูง ปรับขยายได้ง่าย และบำรุงรักษาได้ยาวนาน สร้างขึ้นโดย Kamil Mysliwiec และได้รับแรงบันดาลใจจาก Angular ทำให้มีโครงสร้างที่ชัดเจนและเป็นระบบ
คุณสมบัติเด่นของ NestJS ได้แก่:
- TypeScript-first — เขียนด้วย TypeScript เป็นหลัก ได้ Type Safety ตั้งแต่แรก แต่ยังรองรับ JavaScript ธรรมดาได้
- Angular-inspired Architecture — ใช้แนวคิด Modules, Controllers, Services, Decorators เหมือน Angular ทำให้นักพัฒนาที่คุ้นเคยกับ Angular เรียนรู้ได้เร็ว
- Dependency Injection (DI) — ระบบ DI ที่ทรงพลัง ช่วยให้ Code เป็น Loosely Coupled ทดสอบง่าย
- Platform Agnostic — รองรับทั้ง Express และ Fastify เป็น HTTP Engine ภายใต้
- Rich Ecosystem — มี Module สำเร็จรูปสำหรับ GraphQL, WebSocket, Microservices, CQRS, Database และอีกมากมาย
NestJS vs Express vs Fastify vs Hono — เปรียบเทียบ Framework
| คุณสมบัติ | NestJS | Express | Fastify | Hono |
|---|---|---|---|---|
| TypeScript Support | Built-in (first-class) | ต้องตั้งค่าเอง | มี Plugin | Built-in |
| Architecture Pattern | Opinionated (MVC+DI) | Unopinionated | Plugin-based | Minimal |
| Learning Curve | สูง (แต่คุ้มค่า) | ต่ำมาก | ปานกลาง | ต่ำ |
| Performance (req/s) | ดี (ใช้ Fastify ได้) | ปานกลาง | สูงมาก | สูงมาก |
| Scalability | Enterprise-grade | ต้องจัดการเอง | ดี | ดี |
| Microservices | Built-in support | ไม่มี | ไม่มี | ไม่มี |
| GraphQL | Module สำเร็จรูป | ต้องติดตั้งเอง | ต้องติดตั้งเอง | ต้องติดตั้งเอง |
| Testing | Built-in test utilities | ต้องจัดการเอง | มี Plugin | ต้องจัดการเอง |
| เหมาะกับ | Enterprise/ระบบใหญ่ | ระบบเล็ก/เรียนรู้ | API ประสิทธิภาพสูง | Edge/Serverless |
การติดตั้งและเริ่มต้นโปรเจกต์ NestJS
ติดตั้ง NestJS CLI
# ติดตั้ง NestJS CLI แบบ Global
npm install -g @nestjs/cli
# สร้างโปรเจกต์ใหม่
nest new my-enterprise-api
# เลือก Package Manager (npm, yarn, pnpm)
# CLI จะสร้างโครงสร้างโปรเจกต์ให้อัตโนมัติ
# รันโปรเจกต์
cd my-enterprise-api
npm run start:dev # Development mode (hot-reload)
npm run start:prod # Production mode
NestJS CLI Commands ที่ใช้บ่อย
# สร้าง Module
nest generate module users
nest g mo users # ย่อ
# สร้าง Controller
nest generate controller users
nest g co users
# สร้าง Service
nest generate service users
nest g s users
# สร้าง Resource (Module + Controller + Service + DTO + Entity)
nest g resource products
# สร้าง Guard, Pipe, Interceptor, Filter
nest g guard auth
nest g pipe validation
nest g interceptor logging
nest g filter http-exception
โครงสร้างโปรเจกต์ NestJS
NestJS ใช้โครงสร้างแบบ Modular Architecture ที่แบ่ง Code เป็นส่วนๆ ชัดเจน แต่ละส่วนมีหน้าที่เฉพาะ ทำให้ทีมขนาดใหญ่ทำงานร่วมกันได้โดยไม่ชนกัน
src/
├── app.module.ts # Root Module — รวมทุก Module เข้าด้วยกัน
├── app.controller.ts # Root Controller
├── app.service.ts # Root Service
├── main.ts # Entry point — Bootstrap แอป
│
├── users/ # Feature Module
│ ├── users.module.ts # Module definition
│ ├── users.controller.ts # HTTP routes
│ ├── users.service.ts # Business logic
│ ├── dto/ # Data Transfer Objects
│ │ ├── create-user.dto.ts
│ │ └── update-user.dto.ts
│ ├── entities/ # Database entities
│ │ └── user.entity.ts
│ └── users.controller.spec.ts # Unit tests
│
├── auth/ # Auth Module
│ ├── auth.module.ts
│ ├── auth.controller.ts
│ ├── auth.service.ts
│ ├── guards/
│ │ └── jwt-auth.guard.ts
│ └── strategies/
│ └── jwt.strategy.ts
│
├── common/ # Shared utilities
│ ├── filters/
│ ├── interceptors/
│ ├── pipes/
│ └── decorators/
│
└── config/ # Configuration
└── database.config.ts
Modules — หัวใจของ NestJS
Module คือหน่วยพื้นฐานที่ใช้จัดกลุ่ม Code ที่เกี่ยวข้องกันเข้าด้วยกัน ทุก NestJS Application ต้องมีอย่างน้อยหนึ่ง Module คือ Root Module (AppModule)
// users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])], // นำเข้า Module อื่น
controllers: [UsersController], // Controller ของ Module นี้
providers: [UsersService], // Service / Provider
exports: [UsersService], // ส่งออกให้ Module อื่นใช้
})
export class UsersModule {}
Controllers — รับ HTTP Request
Controller ทำหน้าที่รับ HTTP Request จาก Client และส่งต่อให้ Service ประมวลผล โดยใช้ Decorators กำหนด Route, Method และ Parameters
// users.controller.ts
import { Controller, Get, Post, Put, Delete, Param, Body, Query, HttpCode, HttpStatus } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('users') // prefix: /users
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
findAll(@Query('page') page: number = 1, @Query('limit') limit: number = 10) {
return this.usersService.findAll(page, limit);
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(id, updateUserDto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string) {
return this.usersService.remove(id);
}
}
Services — Business Logic
Service เป็นที่รวม Business Logic ทั้งหมด แยกออกจาก Controller เพื่อให้สามารถ Reuse และทดสอบได้ง่าย
// users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const user = this.usersRepository.create(createUserDto);
return this.usersRepository.save(user);
}
async findAll(page: number, limit: number) {
const [items, total] = await this.usersRepository.findAndCount({
skip: (page - 1) * limit,
take: limit,
order: { createdAt: 'DESC' },
});
return { items, total, page, lastPage: Math.ceil(total / limit) };
}
async findOne(id: string): Promise<User> {
const user = await this.usersRepository.findOne({ where: { id } });
if (!user) throw new NotFoundException(`User #${id} not found`);
return user;
}
async update(id: string, updateUserDto: any): Promise<User> {
await this.usersRepository.update(id, updateUserDto);
return this.findOne(id);
}
async remove(id: string): Promise<void> {
const result = await this.usersRepository.delete(id);
if (result.affected === 0) throw new NotFoundException(`User #${id} not found`);
}
}
Dependency Injection (DI) — ระบบหัวใจของ NestJS
Dependency Injection คือ Design Pattern ที่ NestJS ใช้เป็นแกนหลัก แทนที่จะสร้าง Instance ของ Class ด้วยตัวเอง (new MyService()) เราให้ NestJS Container จัดการสร้างและส่ง Dependencies ให้อัตโนมัติ ข้อดีคือ Code เป็น Loosely Coupled ทดสอบง่าย เปลี่ยน Implementation ได้โดยไม่แก้ Code ที่ใช้งาน
// Custom Provider — ใช้เปลี่ยน Implementation ได้
@Module({
providers: [
{
provide: 'PAYMENT_SERVICE',
useClass: process.env.NODE_ENV === 'production'
? StripePaymentService
: MockPaymentService,
},
{
provide: 'CONFIG',
useValue: { apiKey: process.env.API_KEY, timeout: 5000 },
},
{
provide: 'ASYNC_CONNECTION',
useFactory: async (configService: ConfigService) => {
const dbConfig = configService.get('database');
return createConnection(dbConfig);
},
inject: [ConfigService],
},
],
})
export class PaymentModule {}
Decorators — ฟีเจอร์ที่ทำให้ NestJS สวยงาม
NestJS ใช้ Decorators อย่างหนักเพื่อกำหนดพฤติกรรมของ Class, Method และ Parameter โดยไม่ต้องเขียน Boilerplate Code มากมาย Decorator ที่สำคัญมีหลายกลุ่ม เช่น @Controller, @Get, @Post สำหรับ Routing และ @Injectable สำหรับ DI
// Custom Decorator — สร้าง Decorator เอง
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user?.[data] : user;
},
);
// ใช้งาน
@Get('profile')
getProfile(@CurrentUser() user: User) {
return user;
}
@Get('email')
getEmail(@CurrentUser('email') email: string) {
return { email };
}
Pipes — Validation และ Transformation
Pipes ใน NestJS ทำหน้าที่สองอย่าง: Validation (ตรวจสอบข้อมูล) และ Transformation (แปลงข้อมูล) ทำงานก่อนที่ข้อมูลจะถึง Controller Method ทำให้มั่นใจได้ว่าข้อมูลที่เข้ามาถูกต้องเสมอ
// DTO พร้อม Validation ด้วย class-validator
import { IsEmail, IsString, MinLength, IsOptional, IsEnum } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(2)
name: string;
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsEnum(['admin', 'user', 'moderator'])
role?: string;
}
// เปิดใช้ Global Validation Pipe ใน main.ts
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({
whitelist: true, // ตัด Property ที่ไม่ได้กำหนดใน DTO ออก
forbidNonWhitelisted: true, // ถ้ามี Property แปลกๆ ให้ Error
transform: true, // แปลง Type อัตโนมัติ
}));
await app.listen(3000);
}
Guards — Authentication และ Authorization
Guards เป็นกลไกสำหรับควบคุมการเข้าถึง Route โดยตรวจสอบว่า Request มีสิทธิ์เข้าถึงหรือไม่ ใช้สำหรับ Authentication (ตรวจว่า Login หรือยัง) และ Authorization (ตรวจว่ามีสิทธิ์หรือไม่)
// JWT Auth Guard
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(' ')[1];
if (!token) return false;
try {
const payload = await this.jwtService.verifyAsync(token);
request.user = payload;
return true;
} catch {
return false;
}
}
}
// Roles Guard
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
if (!requiredRoles) return true;
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some(role => user.roles?.includes(role));
}
}
// ใช้งาน
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Delete(':id')
removeUser(@Param('id') id: string) {
return this.usersService.remove(id);
}
Interceptors — จัดการ Request/Response
Interceptors สามารถแทรกตัวเข้าไปก่อนและหลังการทำงานของ Controller Method ใช้สำหรับ Logging, Caching, Response Transformation หรือ Error Handling
// Logging Interceptor — จับเวลาทุก Request
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const method = request.method;
const url = request.url;
const now = Date.now();
return next.handle().pipe(
tap(() => console.log(`${method} ${url} - ${Date.now() - now}ms`)),
);
}
}
// Transform Interceptor — ห่อ Response ในรูปแบบมาตรฐาน
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(data => ({ success: true, data, timestamp: new Date().toISOString() })),
);
}
}
Exception Filters — จัดการ Error อย่างเป็นระบบ
Exception Filters จับ Error ที่เกิดขึ้นในแอป และแปลงเป็น HTTP Response ที่เหมาะสม ทำให้ Client ได้รับ Error Message ที่สม่ำเสมอ
// Custom Exception Filter
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message = exception instanceof HttpException
? exception.getResponse()
: 'Internal server error';
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message,
});
}
}
Middleware — จัดการ Request ก่อนถึง Route
Middleware ใน NestJS ทำงานเหมือน Express Middleware ทำงานก่อนที่ Request จะถึง Guard, Interceptor หรือ Controller เหมาะสำหรับ CORS, Logging, Rate Limiting หรือ Request Parsing
// Custom Middleware
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
next();
}
}
// ลงทะเบียนใน Module
@Module({ /* ... */ })
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('*'); // ใช้กับทุก Route
}
}
Database Integration — TypeORM, Prisma, Sequelize
NestJS รองรับ ORM หลายตัว โดยมี Official Module สำเร็จรูปให้ใช้ สามารถเลือกใช้ได้ตามความถนัดและความต้องการของโปรเจกต์
TypeORM (แนะนำสำหรับ NestJS)
// Entity
@Entity()
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column({ unique: true })
email: string;
@Column()
password: string;
@CreateDateColumn()
createdAt: Date;
@OneToMany(() => Post, post => post.author)
posts: Post[];
}
// app.module.ts
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'admin',
password: 'secret',
database: 'myapp',
entities: [User, Post],
synchronize: false, // อย่าใช้ true ใน Production
}),
],
})
Prisma Integration
// prisma.service.ts
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}
}
// ใช้งานใน Service
@Injectable()
export class UsersService {
constructor(private prisma: PrismaService) {}
async findAll() {
return this.prisma.user.findMany({
include: { posts: true },
});
}
}
Swagger/OpenAPI — Auto-generate API Documentation
NestJS มี Module สำหรับสร้างเอกสาร API อัตโนมัติด้วย Swagger/OpenAPI ช่วยให้ทีม Frontend และทีมอื่นเข้าใจ API ได้ง่ายโดยไม่ต้องเขียนเอกสารแยก
// main.ts — ตั้งค่า Swagger
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
const config = new DocumentBuilder()
.setTitle('My Enterprise API')
.setDescription('API Documentation')
.setVersion('1.0')
.addBearerAuth()
.addTag('users')
.addTag('products')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);
// เข้าถึงได้ที่ http://localhost:3000/api/docs
// ใส่ Decorator ใน DTO เพื่อสร้างเอกสาร
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ example: 'John Doe', description: 'ชื่อผู้ใช้' })
name: string;
@ApiProperty({ example: 'john@example.com' })
email: string;
}
GraphQL กับ NestJS
NestJS รองรับ GraphQL แบบ First-class ทั้ง Code-first และ Schema-first approach สามารถสร้าง GraphQL API ที่มีโครงสร้างชัดเจนและทรงพลังได้อย่างง่ายดาย
// Code-first approach
// users.resolver.ts
@Resolver(() => User)
export class UsersResolver {
constructor(private usersService: UsersService) {}
@Query(() => [User])
async users() {
return this.usersService.findAll();
}
@Query(() => User)
async user(@Args('id') id: string) {
return this.usersService.findOne(id);
}
@Mutation(() => User)
async createUser(@Args('input') input: CreateUserInput) {
return this.usersService.create(input);
}
@ResolveField(() => [Post])
async posts(@Parent() user: User) {
return this.postsService.findByUserId(user.id);
}
}
WebSocket กับ NestJS
NestJS มี Module สำหรับ WebSocket ที่ทำงานร่วมกับ Socket.IO หรือ WS ได้ ใช้สำหรับ Real-time Communication เช่น Chat, Notifications, Live Dashboard
// chat.gateway.ts
@WebSocketGateway({ cors: true })
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer()
server: Server;
handleConnection(client: Socket) {
console.log(`Client connected: ${client.id}`);
}
handleDisconnect(client: Socket) {
console.log(`Client disconnected: ${client.id}`);
}
@SubscribeMessage('sendMessage')
handleMessage(client: Socket, payload: { room: string; message: string }) {
this.server.to(payload.room).emit('newMessage', {
sender: client.id,
message: payload.message,
timestamp: new Date(),
});
}
@SubscribeMessage('joinRoom')
handleJoinRoom(client: Socket, room: string) {
client.join(room);
client.emit('joinedRoom', room);
}
}
Microservices กับ NestJS
หนึ่งในจุดเด่นของ NestJS คือ Built-in Microservices Support รองรับ Transport Layer หลายแบบ ทำให้สร้างระบบ Microservices ได้ง่ายโดยไม่ต้องพึ่ง Library ภายนอก
| Transport | Use Case | ข้อดี |
|---|---|---|
| TCP | Service-to-service ภายใน | ง่าย ไม่ต้องพึ่ง Broker |
| Redis | Pub/Sub, Event-driven | เร็ว ใช้ Redis เป็น Broker |
| NATS | Cloud-native messaging | เบา ประสิทธิภาพสูง |
| Kafka | Event streaming ขนาดใหญ่ | ทนทาน ไม่ตกหล่น |
| gRPC | High-performance RPC | Binary protocol เร็วมาก |
| RabbitMQ | Message queue ทั่วไป | Reliable, flexible routing |
// Microservice Server (TCP)
// main.ts
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.TCP,
options: { host: '0.0.0.0', port: 3001 },
});
await app.listen();
// Message Pattern
@Controller()
export class OrdersController {
@MessagePattern('get_order')
getOrder(data: { id: string }) {
return this.ordersService.findOne(data.id);
}
@EventPattern('order_created')
handleOrderCreated(data: any) {
// Fire-and-forget event
this.notificationService.notify(data);
}
}
// Client — เรียกใช้ Microservice อื่น
@Injectable()
export class ApiGatewayService {
constructor(@Inject('ORDERS_SERVICE') private ordersClient: ClientProxy) {}
async getOrder(id: string) {
return this.ordersClient.send('get_order', { id }).toPromise();
}
}
CQRS Module — Command Query Responsibility Segregation
NestJS มี CQRS Module ให้ใช้สำหรับแอปที่ซับซ้อน โดยแยก Command (เปลี่ยนแปลงข้อมูล) ออกจาก Query (อ่านข้อมูล) ทำให้ระบบ Scale ได้ดีขึ้น แต่ละส่วนปรับแต่งได้อิสระ เหมาะกับระบบที่มี Read/Write ratio ต่างกันมาก เช่น ระบบ E-commerce ที่อ่านสินค้าเยอะแต่สั่งซื้อน้อยกว่า
// Command
export class CreateOrderCommand {
constructor(
public readonly userId: string,
public readonly items: OrderItem[],
) {}
}
// Command Handler
@CommandHandler(CreateOrderCommand)
export class CreateOrderHandler implements ICommandHandler<CreateOrderCommand> {
async execute(command: CreateOrderCommand) {
// Create order logic
// Publish event
this.eventBus.publish(new OrderCreatedEvent(order.id));
}
}
Testing ใน NestJS
NestJS มี Testing Utilities ที่ทรงพลังสำหรับทั้ง Unit Test และ E2E Test ใช้ Jest เป็น Test Runner หลัก พร้อมเครื่องมือสำหรับ Mock Dependencies อย่างง่ายดาย
Unit Test
// users.service.spec.ts
describe('UsersService', () => {
let service: UsersService;
let repository: Repository<User>;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
UsersService,
{
provide: getRepositoryToken(User),
useValue: {
find: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
save: jest.fn(),
},
},
],
}).compile();
service = module.get(UsersService);
repository = module.get(getRepositoryToken(User));
});
it('should find a user by id', async () => {
const mockUser = { id: '1', name: 'Test', email: 'test@test.com' };
jest.spyOn(repository, 'findOne').mockResolvedValue(mockUser as User);
const result = await service.findOne('1');
expect(result).toEqual(mockUser);
});
});
E2E Test
// test/users.e2e-spec.ts
describe('Users (e2e)', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/users (POST)', () => {
return request(app.getHttpServer())
.post('/users')
.send({ name: 'Test', email: 'test@test.com', password: '12345678' })
.expect(201)
.expect(res => {
expect(res.body.name).toBe('Test');
});
});
afterAll(async () => {
await app.close();
});
});
Deployment — Docker และ Kubernetes
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["node", "dist/main.js"]
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://admin:secret@db:5432/myapp
- JWT_SECRET=your-secret-key
depends_on:
- db
- redis
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
pgdata:
Monorepo Support
NestJS CLI รองรับ Monorepo Mode ให้จัดการหลาย Application และ Library ในโปรเจกต์เดียว เหมาะกับ Microservices Architecture ที่ต้องการแชร์ Code ระหว่าง Service
# สร้าง Monorepo
nest new my-workspace --monorepo
# เพิ่ม Application
nest generate app orders-service
nest generate app notifications-service
# เพิ่ม Library (shared code)
nest generate library common
nest generate library database
# Build แต่ละ App
nest build orders-service
nest build notifications-service
เมื่อไหร่ควรเลือก NestJS?
NestJS ไม่ใช่ Framework สำหรับทุกโปรเจกต์ การเลือกใช้ควรพิจารณาจากขนาดและความซับซ้อนของระบบ จำนวนคนในทีม และแผนระยะยาวของโปรเจกต์ ถ้าโปรเจกต์เป็น Prototype หรือ MVP ขนาดเล็ก Express หรือ Hono อาจเหมาะกว่าเพราะเริ่มต้นเร็ว แต่ถ้าเป็นระบบที่ต้องบำรุงรักษาหลายปี มีทีมหลายคน ต้องการโครงสร้างที่ชัดเจน NestJS คือคำตอบ
- ใช้ NestJS เมื่อ: ระบบ Enterprise, ทีมใหญ่ 5+ คน, ต้องการ Microservices, GraphQL, WebSocket, CQRS, ต้องการ Code ที่มีโครงสร้างชัดเจนและ Testable
- ไม่จำเป็นต้องใช้เมื่อ: โปรเจกต์เล็ก Prototype MVP, ทีม 1-2 คน ที่ต้องการความเร็วในการพัฒนา, Serverless Functions ที่มีแค่ไม่กี่ Endpoint
สรุป
NestJS เป็น Framework ที่ทรงพลังสำหรับ Enterprise Backend Development บน Node.js ด้วยโครงสร้างที่ได้รับแรงบันดาลใจจาก Angular ระบบ Dependency Injection ที่แข็งแกร่ง และ Ecosystem ที่ครอบคลุมทั้ง REST API, GraphQL, WebSocket, Microservices และ CQRS ทำให้เป็น Framework ที่เหมาะสมที่สุดสำหรับระบบ Backend ขนาดใหญ่ที่ต้องการความเป็นระเบียบ Scalable และ Maintainable ในระยะยาว
ในปี 2026 NestJS ยังคงเป็นตัวเลือกอันดับหนึ่งสำหรับองค์กรที่ต้องการสร้าง Backend ด้วย Node.js อย่างมืออาชีพ เริ่มต้นด้วย CLI สร้างโปรเจกต์แรก ลองสร้าง CRUD API ด้วย Module Controller Service แล้วคุณจะเข้าใจว่าทำไม NestJS ถึงได้รับความนิยมมากขนาดนี้
