React & Next.js Topic
Introduction to NestJS
What is NestJS?
NestJS is a progressive, TypeScript-first Node.js framework for building efficient, reliable, and scalable server-side applications. It combines elements of:
-
Object-Oriented Programming (OOP)
-
Functional Programming (FP)
-
Functional Reactive Programming (FRP)
Built on top of Express.js (or optionally Fastify), NestJS provides an out-of-the-box application architecture that helps developers create highly testable, scalable, and maintainable applications.
Key Features:
-
Built-in TypeScript support (also supports JavaScript)
-
Modular architecture inspired by Angular
-
Dependency Injection system
-
Extensive ecosystem of modules
-
Excellent for building microservices, REST APIs, GraphQL APIs, and real-time applications
-
Strong emphasis on testing
Architecture Overview
1. Modules
Modules are the building blocks of NestJS applications. Each application has at least one module (the root module). Modules organize code into cohesive blocks of functionality.
typescript
@Module({
imports: [/* other modules */],
controllers: [/* controllers */],
providers: [/* services */],
exports: [/* providers to export */],
})
export class AppModule {}
2. Controllers
Controllers handle incoming HTTP requests and return responses. They define routes and delegate business logic to providers.
typescript
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'All users';
}
}
3. Providers
Providers are services, repositories, factories, etc., that can be injected into controllers or other providers. The most common type is a Service.
typescript
@Injectable()
export class UsersService {
private users = [];
findAll() {
return this.users;
}
}
4. Dependency Injection
NestJS has a built-in IoC (Inversion of Control) container that manages dependencies automatically.
Setting Up a Basic REST API Project
Step 1: Prerequisites
-
Node.js (v16 or newer)
-
npm or yarn
-
Basic TypeScript knowledge
Step 2: Install NestJS CLI
bash
npm install -g @nestjs/cli # or yarn global add @nestjs/cli
Step 3: Create a New Project
bash
nest new project-name # Choose your package manager (npm or yarn)
Step 4: Project Structure
text
project-name/ ├── src/ │ ├── app.controller.ts │ ├── app.controller.spec.ts │ ├── app.module.ts │ ├── app.service.ts │ └── main.ts ├── test/ ├── nest-cli.json ├── package.json ├── tsconfig.json └── README.md
Step 5: Create a Basic REST API
1. Generate Resources:
bash
nest generate module users nest generate controller users nest generate service users
2. User Entity (optional):
typescript
// src/users/entities/user.entity.ts
export class User {
id: number;
name: string;
email: string;
}
3. User Service:
typescript
// src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { User } from './entities/user.entity';
@Injectable()
export class UsersService {
private users: User[] = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' },
];
findAll(): User[] {
return this.users;
}
findOne(id: number): User {
return this.users.find(user => user.id === id);
}
create(user: Omit<User, 'id'>): User {
const newUser = {
id: this.users.length + 1,
...user,
};
this.users.push(newUser);
return newUser;
}
update(id: number, updatedUser: Partial<User>): User {
const index = this.users.findIndex(user => user.id === id);
this.users[index] = { ...this.users[index], ...updatedUser };
return this.users[index];
}
remove(id: number): boolean {
const index = this.users.findIndex(user => user.id === id);
if (index > -1) {
this.users.splice(index, 1);
return true;
}
return false;
}
}
4. User Controller:
typescript
// src/users/users.controller.ts
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
ParseIntPipe,
HttpCode,
HttpStatus
} from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(): User[] {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number): User {
return this.usersService.findOne(id);
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() user: Omit<User, 'id'>): User {
return this.usersService.create(user);
}
@Put(':id')
update(
@Param('id', ParseIntPipe) id: number,
@Body() updatedUser: Partial<User>,
): User {
return this.usersService.update(id, updatedUser);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id', ParseIntPipe) id: number): void {
this.usersService.remove(id);
}
}
5. User Module:
typescript
// src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
6. Update App Module:
typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Step 6: Run the Application
Development mode (with hot reload):
bash
npm run start:dev
Production mode:
bash
npm run build npm run start:prod
Step 7: Test the API
Use Postman, cURL, or any API client:
bash
# Get all users
curl http://localhost:3000/users
# Get single user
curl http://localhost:3000/users/1
# Create user
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"alice@example.com"}'
# Update user
curl -X PUT http://localhost:3000/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"John Updated"}'
# Delete user
curl -X DELETE http://localhost:3000/users/1
Step 8: Add Validation (Optional)
Install class-validator and class-transformer:
bash
npm install class-validator class-transformer
Update main.ts to enable validation:
typescript
// src/main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable validation globally
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}));
await app.listen(3000);
}
bootstrap();
Create a DTO (Data Transfer Object):
typescript
// src/users/dto/create-user.dto.ts
import { IsEmail, IsString, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(2)
name: string;
@IsEmail()
email: string;
}
Update the controller to use DTO:
typescript
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: CreateUserDto): User {
return this.usersService.create(createUserDto);
}
In Short
You've now set up a basic NestJS REST API with:
-
✅ Project initialization
-
✅ Modular architecture
-
✅ CRUD operations
-
✅ Controllers, Services, and Modules
-
✅ Basic validation (optional)
NestJS provides much more including:
-
Guards for authentication
-
Interceptors for request/response transformation
-
Pipes for data transformation/validation
-
Custom decorators
-
WebSockets support
-
GraphQL support
-
Microservices architecture
-
Testing utilities
The framework's structured approach makes it excellent for large-scale applications where maintainability and scalability are crucial.
Comments (0)
No comments yet. Be the first to comment!