Track A · Tutorial 2

Advanced NestJS & TypeScript

Chapter 24 · Backend Specialization
~3 hours Advanced Database · JWT · Testing · Interceptors

Overview

This tutorial takes you beyond the basics. You will integrate a database using Prisma or TypeORM, add validation with DTOs, implement JWT authentication, and write unit and end‑to‑end tests. You'll also learn about middleware, interceptors, and advanced TypeScript patterns.

Why this matters: Real‑world applications need persistence, security, and reliability. These are the skills that separate junior from senior developers.

1. Middleware & Interceptors

Middleware

Middleware runs before the route handler. Use it for logging, authentication, or transforming the request.

// logger.middleware.ts import { Injectable, NestMiddleware } from '@nestjs/common'; @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: any, res: any, next: () => void) { console.log(`Request: ${req.method} ${req.url}`); next(); } }

Interceptors

Interceptors transform the response or handle cross‑cutting concerns like logging, caching, or serialisation.

// transform.interceptor.ts import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { map } from 'rxjs/operators'; @Injectable() export class TransformInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler) { return next.handle().pipe(map(data => ({ data, status: 'success' }))); } }

2. Database Integration

NestJS integrates seamlessly with Prisma and TypeORM.

Prisma (recommended)

npm install @prisma/client npx prisma init // schema.prisma model User { id Int @id @default(autoincrement()) email String @unique name String posts Post[] }

Prisma Service

@Injectable() export class PrismaService extends PrismaClient implements OnModuleInit { async onModuleInit() { await this.$connect(); } }

Using Prisma in a Service

@Injectable() export class UsersService { constructor(private prisma: PrismaService) {} async findAll() { return this.prisma.user.findMany(); } }

3. Validation & DTOs

Use class-validator and class-transformer for automatic validation. NestJS provides a global validation pipe.

npm install class-validator class-transformer // create-user.dto.ts import { IsEmail, IsString, MinLength } from 'class-validator'; export class CreateUserDto { @IsEmail() email: string; @IsString() @MinLength(2) name: string; }
// main.ts – enable global validation app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, }));

4. Authentication (JWT)

Implement JWT authentication with Passport and the NestJS JWT module.

npm install @nestjs/jwt @nestjs/passport passport passport-jwt npm install -D @types/passport-jwt
// jwt.strategy.ts import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.JWT_SECRET, }); } async validate(payload: any) { return { userId: payload.sub, email: payload.email }; } }
// auth.controller.ts @Post('login') async login(@Body() loginDto: LoginDto) { const user = await this.authService.validateUser(loginDto); return this.authService.login(user); }
Protect routes: Use @UseGuards(AuthGuard('jwt')) on controllers or methods.

5. Testing (Unit & E2E)

NestJS uses Jest for testing.

Unit Test

// users.service.spec.ts describe('UsersService', () => { let service: UsersService; let prisma: PrismaService; beforeEach(async () => { const module = await Test.createTestingModule({ providers: [UsersService, PrismaService], }).compile(); service = module.get(UsersService); }); it('should find all users', async () => { const users = await service.findAll(); expect(users).toBeDefined(); }); });

E2E Test

// app.e2e-spec.ts describe('AppController (e2e)', () => { let app: INestApplication; beforeAll(async () => { const module = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = module.createNestApplication(); await app.init(); }); it('/users (GET)', () => { return request(app.getHttpServer()) .get('/users') .expect(200); }); });

Quiz

Question 1

Which decorator is used to protect a route with JWT authentication?

  • @UseGuards(AuthGuard('jwt'))
  • @JwtAuth()
  • @Authenticated()
  • @Secure()
Show answer
A. @UseGuards(AuthGuard('jwt')).

Question 2

Which library is used for DTO validation in NestJS?

  • joi
  • class-validator
  • yup
  • zod
Show answer
B. class-validator.

Question 3

What is the purpose of an interceptor in NestJS?

  • To log requests
  • To transform responses or handle cross‑cutting concerns
  • To connect to the database
  • To define routes
Show answer
B. To transform responses or handle cross‑cutting concerns.

Exercises

Exercise 1

Create a Prisma model for a Product with fields: id, name, price, and category.

Sample answer
model Product { id Int @id @default(autoincrement()) name String price Float category String }

Exercise 2

Write a ValidationPipe configuration that strips extra fields (whitelist) and throws an error if extra fields are present.

Sample answer
app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, }));

Homework

Homework 1

Extend the Task Management API from Tutorial 1 with Prisma. Add a User model and associate tasks with users. Implement JWT authentication so users can only see their own tasks.

Sample outline
  • Update schema.prisma with User and Task models (userId FK).
  • Add AuthModule, JwtStrategy, and AuthGuard.
  • Add @UseGuards(AuthGuard('jwt')) to all task endpoints.
  • Modify TasksService to filter tasks by the authenticated user's ID (extracted from the JWT payload).

Mini‑Project

Blog API with Authentication

Build a full blog API with NestJS:

  • Users: Register, login (JWT)
  • Posts: CRUD operations (authenticated)
  • Comments: CRUD operations
  • Use Prisma for data persistence
  • Add validation with DTOs
  • Write at least one unit test and one e2e test
Sample implementation outline
  • Modules: AuthModule, UsersModule, PostsModule, CommentsModule
  • Auth: Register (POST /auth/register), Login (POST /auth/login)
  • Posts: GET /posts, GET /posts/:id, POST /posts, PUT /posts/:id, DELETE /posts/:id
  • Comments: GET /posts/:postId/comments, POST /posts/:postId/comments
  • Prisma schema: User, Post (userId, title, content), Comment (postId, userId, content)

Tutorial Summary

You mastered advanced NestJS concepts: middleware, interceptors, database integration with Prisma, DTO validation, JWT authentication, and testing. You now have the skills to build production‑ready, secure, and testable backend applications with NestJS and TypeScript.

Key takeaway: NestJS's ecosystem provides all the building blocks for enterprise‑grade applications. Combine them with TypeScript's type safety for a robust development experience.