Введение в NestJS
NestJS (Nest) — это прогрессивный фреймворк для создания эффективных, масштабируемых и надежных серверных приложений на Node.js. Он использует TypeScript в качестве основного языка и вдохновлен архитектурой Angular. NestJS предоставляет готовую архитектуру приложения, которая помогает разработчикам создавать хорошо структурированный, тестируемый и поддерживаемый код.
Основная цель NestJS — решить проблему отсутствия четкой архитектуры в экосистеме Node.js. В отличие от Express или Fastify, которые являются минималистичными и не навязывают структуру, NestJS предлагает готовые абстракции: модули, контроллеры, сервисы, провайдеры и middleware. Это особенно полезно для крупных корпоративных проектов, где важна предсказуемость и стандартизация кода.
NestJS построен поверх HTTP-фреймворков (по умолчанию Express, но можно использовать Fastify) и добавляет к ним мощную систему внедрения зависимостей (Dependency Injection), декораторы, Guards, Interceptors, Pipes и Filters. Фреймворк активно использует декораторы TypeScript, что делает код декларативным и читаемым.
Установка NestJS
Для установки NestJS вам потребуется Node.js (версия 16 или выше) и менеджер пакетов npm (или yarn, pnpm).
Самый простой способ начать — использовать Nest CLI:
npm install -g @nestjs/cli
nest new my-nest-project
cd my-nest-project
npm run start:dev
Если вы предпочитаете установить NestJS в уже существующий проект:
npm install @nestjs/core @nestjs/common @nestjs/platform-express reflect-metadata rxjs typescript @types/node
Также потребуется установить TypeScript и ts-node для разработки:
npm install -D typescript @types/node ts-node
Важно: NestJS использует библиотеку reflect-metadata для работы с декораторами. Убедитесь, что она импортирована в главном файле main.ts:
import "reflect-metadata";
Быстрый старт с примером кода
Создадим простое REST API приложение с одним эндпоинтом, который возвращает приветствие.
Структура проекта:
src/
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts
main.ts — точка входа:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log('Server is running on http://localhost:3000');
}
bootstrap();
app.module.ts — корневой модуль:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
app.controller.ts — контроллер:
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
app.service.ts — сервис (бизнес-логика):
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
Запустите приложение командой npm run start:dev и откройте http://localhost:3000. Вы увидите "Hello World!".
Основные методы и функции NestJS
Рассмотрим 10 ключевых элементов NestJS, которые используются в каждом проекте.
1. @Module() — декоратор модуля
Что делает: Определяет класс как модуль NestJS. Модуль — это контейнер для контроллеров, сервисов и других модулей. Он организует приложение в логические блоки.
Параметры:
imports— массив импортируемых модулейcontrollers— массив контроллеров, принадлежащих модулюproviders— массив сервисов/провайдеровexports— массив провайдеров, которые будут доступны другим модулям
Пример:
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { DatabaseModule } from '../database/database.module';
@Module({
imports: [DatabaseModule],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
2. @Controller() — декоратор контроллера
Что делает: Определяет класс как контроллер, который обрабатывает входящие HTTP-запросы. Можно указать префикс маршрута.
Параметры: prefix (строка) — префикс для всех маршрутов в контроллере.
Пример:
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string {
return 'This action returns all users';
}
}
// Маршрут: GET /users
3. @Injectable() — декоратор сервиса
Что делает: Помечает класс как провайдер, который может быть внедрен через Dependency Injection. Обычно используется для сервисов, репозиториев, фабрик.
Параметры: Нет обязательных параметров.
Пример:
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
private readonly users = [];
findAll() {
return this.users;
}
create(user) {
this.users.push(user);
}
}
4. @Get(), @Post(), @Put(), @Delete() — декораторы HTTP методов
Что делает: Привязывают метод контроллера к конкретному HTTP-методу и пути. Позволяют создавать RESTful эндпоинты.
Параметры: path (строка, опционально) — дополнительный путь к маршруту.
Пример:
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(): string { return 'GET all users'; }
@Get(':id')
findOne(@Param('id') id: string): string {
return `GET user with id ${id}`;
}
@Post()
create(@Body() createUserDto: any): string {
return `POST create user: ${JSON.stringify(createUserDto)}`;
}
}
5. @Param() — декоратор параметра маршрута
Что делает: Извлекает параметры из URL (например, /users/:id). Позволяет получить доступ к динамическим сегментам пути.
Параметры: property (строка, опционально) — имя параметра. Если не указан, возвращает весь объект params.
Пример:
@Get(':id')
findOne(@Param('id') id: string): string {
return `User ID: ${id}`;
}
@Get(':id/:name')
findByName(@Param() params: any): string {
return `ID: ${params.id}, Name: ${params.name}`;
}
6. @Body() — декоратор тела запроса
Что делает: Извлекает тело POST/PUT/PATCH запроса. Обычно используется вместе с DTO (Data Transfer Object) для валидации.
Параметры: Нет обязательных параметров.
Пример:
import { IsString, IsInt } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
@IsInt()
age: number;
}
@Post()
create(@Body() createUserDto: CreateUserDto): string {
return `User created: ${createUserDto.name}, ${createUserDto.age}`;
}
7. @Query() — декоратор query-параметров
Что делает: Извлекает параметры из строки запроса (query string), например /users?page=1&limit=10.
Параметры: property (строка, опционально) — имя параметра.
Пример:
@Get()
findAll(@Query('page') page: number = 1, @Query('limit') limit: number = 10): string {
return `Page: ${page}, Limit: ${limit}`;
}
@Get('search')
search(@Query() query: any): string {
return `Search query: ${JSON.stringify(query)}`;
}
8. @UsePipes() — декоратор пайпов (валидация и трансформация)
Что делает: Применяет пайпы к контроллеру или методу. Пайпы используются для валидации входных данных и их трансформации. NestJS имеет встроенные пайпы, такие как ValidationPipe, ParseIntPipe, ParseUUIDPipe.
Параметры: Один или несколько экземпляров пайпов.
Пример:
import { Controller, Get, Param, ParseIntPipe, UsePipes, ValidationPipe } from '@nestjs/common';
@Controller('users')
@UsePipes(new ValidationPipe()) // Применяем глобально к контроллеру
export class UsersController {
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number): string {
return `User ID (number): ${id}`;
}
}
9. @UseGuards() — декоратор гардов (авторизация)
Что делает: Применяет гарды к контроллеру или методу. Гарды определяют, может ли запрос быть обработан (например, проверка JWT токена, роли пользователя).
Параметры: Один или несколько классов гардов.
Пример:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return request.headers.authorization === 'Bearer secret-token';
}
}
@Controller('admin')
@UseGuards(AuthGuard)
export class AdminController {
@Get()
getAdminData(): string {
return 'Admin data';
}
}
10. @Catch() и Exception Filters — фильтры исключений
Что делает: Перехватывает исключения и преобразует их в понятный HTTP-ответ. Позволяет централизованно обрабатывать ошибки.
Параметры: Массив типов исключений для перехвата.
Пример:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const message = exception.message;
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
message: message,
});
}
}
// Использование в контроллере:
@Controller('users')
@UseFilters(new HttpExceptionFilter())
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string): string {
throw new HttpException('User not found', 404);
}
}
Реальный практический пример использования
Создадим полноценный CRUD для управления задачами (Todo list) с использованием TypeORM для работы с базой данных SQLite.