M

Modules & Controllers

Type-safe NestJS modules, controllers, and dependency injection with decorators.

Code

typescript
1// user.entity.ts
2export class User {
3 id: number;
4 name: string;
5 email: string;
6 role: "admin" | "user";
7 createdAt: Date;
8 updatedAt: Date;
9}
10
11// dto/create-user.dto.ts
12import { IsString, IsEmail, IsEnum, IsOptional, MinLength } from "class-validator";
13
14export class CreateUserDto {
15 @IsString()
16 @MinLength(2)
17 name: string;
18
19 @IsEmail()
20 email: string;
21
22 @IsString()
23 @MinLength(8)
24 password: string;
25
26 @IsOptional()
27 @IsEnum(["admin", "user"])
28 role?: "admin" | "user";
29}
30
31// dto/update-user.dto.ts
32import { PartialType } from "@nestjs/mapped-types";
33
34export class UpdateUserDto extends PartialType(CreateUserDto) {}
35
36// dto/query-user.dto.ts
37import { IsOptional, IsInt, Min, Max, IsEnum } from "class-validator";
38import { Type } from "class-transformer";
39
40export class QueryUserDto {
41 @IsOptional()
42 @Type(() => Number)
43 @IsInt()
44 @Min(1)
45 page?: number = 1;
46
47 @IsOptional()
48 @Type(() => Number)
49 @IsInt()
50 @Min(1)
51 @Max(100)
52 limit?: number = 10;
53
54 @IsOptional()
55 @IsEnum(["admin", "user"])
56 role?: "admin" | "user";
57
58 @IsOptional()
59 @IsString()
60 search?: string;
61}
62
63// user.service.ts
64import { Injectable, NotFoundException, ConflictException } from "@nestjs/common";
65
66@Injectable()
67export class UserService {
68 private users: User[] = [];
69 private nextId = 1;
70
71 async findAll(query: QueryUserDto): Promise<{ data: User[]; total: number }> {
72 let result = this.users;
73
74 if (query.role) {
75 result = result.filter((u) => u.role === query.role);
76 }
77
78 if (query.search) {
79 const search = query.search.toLowerCase();
80 result = result.filter(
81 (u) =>
82 u.name.toLowerCase().includes(search) ||
83 u.email.toLowerCase().includes(search)
84 );
85 }
86
87 const total = result.length;
88 const start = (query.page! - 1) * query.limit!;
89 const data = result.slice(start, start + query.limit!);
90
91 return { data, total };
92 }
93
94 async findOne(id: number): Promise<User> {
95 const user = this.users.find((u) => u.id === id);
96 if (!user) {
97 throw new NotFoundException(`User with ID ${id} not found`);
98 }
99 return user;
100 }
101
102 async create(dto: CreateUserDto): Promise<User> {
103 const existingUser = this.users.find((u) => u.email === dto.email);
104 if (existingUser) {
105 throw new ConflictException("Email already in use");
106 }
107
108 const user: User = {
109 id: this.nextId++,
110 name: dto.name,
111 email: dto.email,
112 role: dto.role || "user",
113 createdAt: new Date(),
114 updatedAt: new Date(),
115 };
116
117 this.users.push(user);
118 return user;
119 }
120
121 async update(id: number, dto: UpdateUserDto): Promise<User> {
122 const user = await this.findOne(id);
123
124 if (dto.email && dto.email !== user.email) {
125 const existingUser = this.users.find((u) => u.email === dto.email);
126 if (existingUser) {
127 throw new ConflictException("Email already in use");
128 }
129 }
130
131 Object.assign(user, dto, { updatedAt: new Date() });
132 return user;
133 }
134
135 async remove(id: number): Promise<void> {
136 const index = this.users.findIndex((u) => u.id === id);
137 if (index === -1) {
138 throw new NotFoundException(`User with ID ${id} not found`);
139 }
140 this.users.splice(index, 1);
141 }
142}
143
144// user.controller.ts
145import {
146 Controller,
147 Get,
148 Post,
149 Patch,
150 Delete,
151 Body,
152 Param,
153 Query,
154 ParseIntPipe,
155 HttpCode,
156 HttpStatus,
157} from "@nestjs/common";
158
159@Controller("users")
160export class UserController {
161 constructor(private readonly userService: UserService) {}
162
163 @Get()
164 async findAll(@Query() query: QueryUserDto) {
165 return this.userService.findAll(query);
166 }
167
168 @Get(":id")
169 async findOne(@Param("id", ParseIntPipe) id: number) {
170 return this.userService.findOne(id);
171 }
172
173 @Post()
174 @HttpCode(HttpStatus.CREATED)
175 async create(@Body() dto: CreateUserDto) {
176 return this.userService.create(dto);
177 }
178
179 @Patch(":id")
180 async update(
181 @Param("id", ParseIntPipe) id: number,
182 @Body() dto: UpdateUserDto
183 ) {
184 return this.userService.update(id, dto);
185 }
186
187 @Delete(":id")
188 @HttpCode(HttpStatus.NO_CONTENT)
189 async remove(@Param("id", ParseIntPipe) id: number) {
190 return this.userService.remove(id);
191 }
192}
193
194// user.module.ts
195import { Module } from "@nestjs/common";
196
197@Module({
198 controllers: [UserController],
199 providers: [UserService],
200 exports: [UserService],
201})
202export class UserModule {}

Run this example locally

$ npx @nestjs/cli new my-app