Контроллеры
Что такое контроллер
Контроллер — отвечает за обработку HTTP-запросов. Принимает запрос → вызывает сервис → возвращает ответ.
Создание
nest g controller users
Что создаст:
import { Controller } from '@nestjs/common';
@Controller('users')
export class UsersController {}
'users' — префикс URL.
Базовый контроллер
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'Все пользователи';
}
}
GET /users — вернёт строку.
HTTP-методы
import {
Controller, Get, Post, Put, Patch, Delete,
} from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll() { return []; }
@Get(':id')
findOne(@Param('id') id: string) { return { id }; }
@Post()
create(@Body() data: any) { return data; }
@Put(':id')
update(@Param('id') id: string, @Body() data: any) { return data; }
@Patch(':id')
partialUpdate(@Param('id') id: string, @Body() data: any) { return data; }
@Delete(':id')
remove(@Param('id') id: string) { return { deleted: id }; }
}
Полный CRUD.
Декораторы параметров
@Param() — параметры маршрута:
@Get(':id')
findOne(@Param('id') id: string) {}
@Get(':userId/posts/:postId')
findPost(
@Param('userId') userId: string,
@Param('postId') postId: string,
) {}
@Get(':id')
findAll(@Param() params: { id: string }) {}
@Query() — query-параметры:
@Get()
findAll(
@Query('page') page: string,
@Query('limit') limit: string,
) {}
@Get()
findAll(@Query() query: { page: string; limit: string }) {}
@Body() — тело запроса:
@Post()
create(@Body() data: CreateUserDto) {}
@Post()
create(@Body('email') email: string) {}
@Headers() — заголовки:
@Get()
findAll(@Headers('authorization') auth: string) {}
@Get()
findAll(@Headers() headers: Record<string, string>) {}
@Req(), @Res() — объекты запроса/ответа:
@Get()
findAll(@Req() req: Request) {
return { ip: req.ip };
}
⚠️ @Res() отключает встроенную обработку — используй осторожно.
Динамические маршруты
Параметры:
@Get(':id')
findOne(@Param('id') id: string) {}
@Get(':userId/posts')
findUserPosts(@Param('userId') userId: string) {}
Опциональные:
@Get('search')
search(@Query('q') q?: string) {}
Wildcard:
@Get('files/*')
getFile(@Req() req: Request) {}
Статусы
@HttpCode():
@Post()
@HttpCode(201)
create() {}
@Delete(':id')
@HttpCode(204)
remove() {}
По умолчанию:
GET→ 200.POST→ 201.DELETE→ 200.PUT/PATCH→ 200.
Заголовки ответа
@Get()
@Header('Cache-Control', 'none')
findAll() {}
Redirect
@Get('old')
@Redirect('/new', 301)
redirect() {}
Route-specific middleware
Middleware — через модуль. Guards / Interceptors / Pipes — декораторы.
@Get()
@UseGuards(AuthGuard)
@UseInterceptors(LoggingInterceptor)
@UsePipes(ValidationPipe)
findAll() {}
Контроллер + сервис
Правильная структура:
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Patch(':id')
update(@Param('id') id: string, @Body() dto: UpdateUserDto) {
return this.usersService.update(+id, dto);
}
@Delete(':id')
@HttpCode(204)
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}
Контроллер тонкий — только HTTP. Логика — в сервисе.
Группировка маршрутов
Префикс:
@Controller('api/v1/users')
export class UsersController {}
Глобальный префикс:
main.ts:
app.setGlobalPrefix('api/v1');
Все роуты будут с префиксом.
Версионирование
URI-версия:
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: '1',
});
В контроллере:
@Controller({ path: 'users', version: '2' })
URL: /v2/users.
Валидация параметров
@Param('id', ParseIntPipe):
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
// id — уже number
}
@Query('page', DefaultValuePipe(1), ParseIntPipe):
@Get()
findAll(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
) {}
Ошибка → 400 Bad Request автоматически.
Валидация тела
Через DTO + ValidationPipe:
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
CreateUserDto:
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(2)
name: string;
}
Валидация — на уровне Pipe.
Async-контроллеры
@Get()
async findAll(): Promise<User[]> {
return await this.usersService.findAll();
}
Автоматически ждёт промис.
Обработка ошибок
Бросай исключения:
@Get(':id')
findOne(@Param('id') id: string) {
const user = this.usersService.findOne(+id);
if (!user) {
throw new NotFoundException(`Пользователь ${id} не найден`);
}
return user;
}
Встроенные исключения:
BadRequestException— 400.UnauthorizedException— 401.ForbiddenException— 403.NotFoundException— 404.ConflictException— 409.InternalServerErrorException— 500.
NestJS сам преобразует в JSON.
Формат ошибки
{
"statusCode": 404,
"message": "Пользователь 1 не найден",
"error": "Not Found"
}
Практика: полный CRUD
users.controller.ts:
import {
Controller, Get, Post, Body, Patch, Param,
Delete, HttpCode, ParseIntPipe, NotFoundException,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
const user = this.usersService.findOne(id);
if (!user) {
throw new NotFoundException(`Пользователь ${id} не найден`);
}
return user;
}
@Post()
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Patch(':id')
update(
@Param('id', ParseIntPipe) id: number,
@Body() dto: UpdateUserDto,
) {
return this.usersService.update(id, dto);
}
@Delete(':id')
@HttpCode(204)
remove(@Param('id', ParseIntPipe) id: number) {
return this.usersService.remove(id);
}
}
Проверка:
curl http://localhost:3000/users
curl http://localhost:3000/users/1
curl -X POST http://localhost:3000/users \
-H 'Content-Type: application/json' \
-d '{"name":"Иван","email":"ivan@example.com"}'
Полезные декораторы
@Controller(path)— контроллер.@Get,@Post,@Put,@Patch,@Delete,@Options,@Head— HTTP-методы.@Param,@Query,@Body,@Headers,@Req,@Res,@Session— параметры.@HttpCode,@Header,@Redirect— ответ.@UseGuards,@UseInterceptors,@UsePipes,@UseFilters— обвязка.@SetMetadata— метаданные.
Итог
@Controller— контроллер.@Get,@Post,@Patch,@Delete— методы.@Param,@Query,@Body,@Headers— входные данные.@HttpCode,@Header,@Redirect— ответ.ParseIntPipe— валидация параметров.- Исключения —
NotFoundExceptionи др. - Тонкий контроллер — логика в сервисе.
- Префиксы и версии — через
main.tsи@Controller.
Дальше — сервисы и DI.