Ẩn field nhạy cảm khi trả response: ClassSerializerInterceptor và @Exclude
Dùng class-transformer: đánh dấu @Exclude() (hoặc @Expose với strategy excludeAll) trên entity/DTO và bật ClassSerializerInterceptor để loại field như password khỏi JSON. Interceptor chỉ hoạt động khi trả về instance của class, không phải plain object.
ConfigModule trong NestJS và validate biến môi trường lúc khởi động
ConfigModule.forRoot đọc .env và biến môi trường, cung cấp ConfigService để inject. Dùng validationSchema (Joi) hoặc hàm validate (zod/class-validator) để app fail fast khi thiếu hoặc sai biến. isGlobal: true giúp không phải import ở từng module.
Dependency Injection và IoC container trong NestJS hoạt động ra sao?
Nest có IoC container: lúc bootstrap nó đọc metadata kiểu của constructor (emitDecoratorMetadata), dựng dependency graph, tạo instance (singleton mặc định) và inject vào class cần. Class không tự new dependency, nên dễ mock và thay thế khi test.
Exception Filter trong NestJS là gì? Khi nào cần tự viết?
Exception filter bắt exception chưa được xử lý và định dạng response lỗi. Mặc định Nest tự trả JSON cho HttpException. Tự viết filter bằng @Catch() khi cần format lỗi thống nhất, map lỗi domain/DB sang HTTP status hoặc log tập trung.
Middleware và Guard trong NestJS khác nhau thế nào? Khi nào dùng cái nào?
Middleware chạy sớm nhất, chỉ biết req/res/next, không biết handler nào sẽ chạy; hợp cho logging, CORS, parse. Guard chạy sau middleware, có ExecutionContext nên biết controller/handler và metadata (Reflector); hợp cho authentication/authorization và trả boolean cho phép hay chặn.
Module, Provider và Controller trong NestJS khác nhau thế nào?
Controller nhận request và trả response; Provider (thường là service, gắn @Injectable) chứa logic và được inject; Module (@Module) gom controller/provider lại và quyết định cái gì được export cho module khác dùng.
Tài liệu hoá API NestJS bằng Swagger/OpenAPI như thế nào?
Dùng @nestjs/swagger: DocumentBuilder + SwaggerModule.createDocument/setup tạo OpenAPI spec và UI. Gắn @ApiProperty, @ApiTags, @ApiResponse cho DTO/controller, hoặc bật CLI plugin để tự suy ra metadata từ type TypeScript.
Tạo custom parameter decorator bằng createParamDecorator (ví dụ @CurrentUser)
createParamDecorator nhận (data, ctx: ExecutionContext) và trả giá trị sẽ inject vào tham số handler. Thường dùng để lấy user đã được guard gắn vào request, như @CurrentUser(), giúp controller gọn, không đụng tới req.
ValidationPipe, DTO và class-validator dùng thế nào? whitelist, transform để làm gì?
DTO là class mô tả dữ liệu vào, gắn decorator của class-validator; ValidationPipe validate theo DTO và trả 400 nếu sai. whitelist loại field không khai báo, forbidNonWhitelisted báo lỗi thay vì loại, transform ép payload thành instance DTO và kiểu primitive.
API versioning trong NestJS: URI, header và media type
app.enableVersioning chọn kiểu: URI (/v1/...), HEADER, MEDIA_TYPE hoặc CUSTOM. Khai báo version bằng @Controller({ version: '1' }) hoặc @Version('2') trên handler. Chỉ tăng major khi có breaking change, và cần chính sách deprecation cho phiên bản cũ.
Custom providers: useClass, useValue, useFactory, useExisting dùng khi nào?
Provider có dạng provide + một trong useClass (chọn implementation), useValue (hằng, mock), useFactory (tạo bằng hàm, có thể async và nhận dependency qua inject), useExisting (alias). Token có thể là class, string hoặc Symbol; dùng @Inject(token) để lấy.
E2E test NestJS với Supertest: dựng app, override provider và dọn dữ liệu
Tạo module test bằng Test.createTestingModule({ imports: [AppModule] }), có thể overrideProvider để thay thành phần ngoài, gọi createNestApplication() rồi app.init(), và dùng Supertest request(app.getHttpServer()). Phải áp lại global pipe/filter như main.ts và app.close() ở afterAll.
Interceptor dùng để làm gì? Ví dụ logging, caching, map response
Interceptor implements NestInterceptor, bọc handler bằng RxJS: chạy code trước và sau handler qua next.handle(). Dùng để log thời gian, map/chuẩn hóa response, cache (trả of(cached) mà không gọi handler), timeout, ánh xạ lỗi bằng catchError.
Rate limiting với ThrottlerModule trong NestJS và khi chạy nhiều instance
ThrottlerModule.forRoot cấu hình ttl và limit, đăng ký ThrottlerGuard làm APP_GUARD để giới hạn toàn cục; ghi đè từng route bằng @Throttle hoặc bỏ qua bằng @SkipThrottle. Storage mặc định là in-memory, nên nhiều instance cần storage chia sẻ như Redis. Sau proxy phải cấu hình đúng IP client.
Request lifecycle trong NestJS: thứ tự middleware, guard, interceptor, pipe, filter?
Middleware, rồi Guards, Interceptors (phần trước handler), Pipes, handler, Interceptors (phần sau, theo thứ tự ngược), cuối cùng Exception filters nếu có lỗi. Ở mỗi tầng, thứ tự là global, controller, route.
Transaction trong NestJS với TypeORM: DataSource, QueryRunner và repository pattern
Dùng dataSource.transaction(async manager => ...) hoặc QueryRunner (connect, startTransaction, commit/rollback, release) và thao tác qua manager/queryRunner.manager cùng một connection. Gọi repository inject sẵn sẽ nằm ngoài transaction. Quên release() sẽ leak connection.
Triển khai JWT authentication với Passport trong NestJS
Dùng @nestjs/passport với passport-jwt: JwtStrategy extends PassportStrategy(Strategy) cấu hình cách lấy token và secret, validate() trả về user gắn vào req.user. Bảo vệ route bằng AuthGuard('jwt'). Login ký token bằng JwtService.signAsync.
Unit test service NestJS với Test.createTestingModule và mock provider
Test.createTestingModule dựng module thu nhỏ chỉ với provider cần test; thay dependency thật bằng mock qua { provide, useValue } hoặc overrideProvider(). Gọi compile() rồi module.get() để lấy instance. E2E dùng createNestApplication kèm supertest.
Upload file trong NestJS với FileInterceptor và ParseFilePipe
FileInterceptor bọc multer: @UseInterceptors(FileInterceptor('file')) rồi lấy @UploadedFile(). Dùng ParseFilePipe với MaxFileSizeValidator và FileTypeValidator để kiểm tra, đặt limits trong options của multer, và dùng stream/S3 cho file lớn thay vì giữ trong memory.
Viết RBAC bằng Guard, Reflector và custom decorator như thế nào?
Tạo decorator @Roles() bằng SetMetadata, rồi guard implements CanActivate dùng Reflector.getAllAndOverride đọc metadata từ handler và class, so sánh với req.user.roles. Guard trả boolean; false thì Nest ném 403.
Circular dependency trong NestJS: nguyên nhân, forwardRef và cách tránh
Hai provider (hoặc module) phụ thuộc lẫn nhau khiến Nest không resolve được thứ tự khởi tạo. Cách vá là forwardRef(() => X) kèm @Inject ở cả hai phía (và ở imports của module). Cách tốt hơn là tái cấu trúc: tách service thứ ba hoặc dùng event.
CQRS trong NestJS (@nestjs/cqrs): Command, Query, Event và khi nào nên dùng?
CQRS tách đường ghi (Command, đổi trạng thái) và đường đọc (Query, không side effect). @nestjs/cqrs cung cấp CommandBus, QueryBus, EventBus với handler riêng cho từng loại. Hữu ích khi nghiệp vụ phức tạp, read/write có yêu cầu khác nhau; với CRUD đơn giản thì thừa.
Dynamic module: forRoot, forRootAsync, ConfigModule; global vs scoped module
Dynamic module là module có static method (forRoot/register/forRootAsync) trả về DynamicModule với providers theo cấu hình. forRootAsync nhận useFactory + inject để lấy config bất đồng bộ (vd. từ ConfigService). @Global() làm export khả dụng mọi nơi không cần import.
Lifecycle hooks trong NestJS và graceful shutdown (OnModuleInit, OnApplicationShutdown)
Nest có hook OnModuleInit, OnApplicationBootstrap khi khởi động và OnModuleDestroy, BeforeApplicationShutdown, OnApplicationShutdown khi tắt. Shutdown hook mặc định tắt, phải gọi app.enableShutdownHooks() để Nest lắng nghe SIGTERM và chạy dọn dẹp (đóng DB, queue, drain request).
NestJS microservices: transport, @MessagePattern khác @EventPattern thế nào?
@MessagePattern là request-response: client dùng send(), handler trả giá trị và client chờ. @EventPattern là fire-and-forget: client dùng emit(), không có response, phù hợp thông báo sự kiện. Transport gồm TCP, Redis, NATS, MQTT, RabbitMQ, Kafka, gRPC.
NestJS với Express vs Fastify adapter và các cách tối ưu hiệu năng
Nest tách khỏi HTTP framework bằng adapter: mặc định Express, có thể đổi sang Fastify (FastifyAdapter) để throughput cao hơn nhờ JSON serialization theo schema và overhead thấp. Nhưng middleware/plugin đặc thù Express không dùng trực tiếp. Hiệu năng còn phụ thuộc nhiều vào scope provider, DB và logging.
Provider scope DEFAULT, REQUEST, TRANSIENT khác gì nhau và ảnh hưởng hiệu năng ra sao?
DEFAULT là singleton dùng chung cả app. REQUEST tạo instance mới cho mỗi request, TRANSIENT tạo instance riêng cho mỗi consumer inject. Scope REQUEST có tính lan truyền lên mọi consumer của nó, tốn bộ nhớ và CPU, nên chỉ dùng khi thật cần.
Xử lý job nền với BullMQ trong NestJS: retry, idempotency và scale worker
@nestjs/bullmq dùng Redis làm broker: producer inject Queue và add job, consumer là class @Processor extends WorkerHost. Cấu hình attempts/backoff để retry, removeOnComplete để dọn, và thiết kế handler idempotent vì job có thể chạy lại (at-least-once). Scale bằng nhiều worker và concurrency.