Урок 02

Установка и первый проект

Что понадобится

  • Node.js 20+ (LTS).
  • npm или pnpm.
  • VS Code с расширениями.
  • PostgreSQL или SQLite — для БД.

Nest CLI

Глобально:

npm install -g @nestjs/cli
nest --version

Или через npx — без установки:

npx @nestjs/cli new my-app

Создание проекта

nest new my-app

CLI спросит: какой пакетный менеджер (npm / yarn / pnpm).

Создаст:

my-app/
├── src/
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── test/
│   └── app.e2e-spec.ts
├── .eslintrc.js
├── .prettierrc
├── nest-cli.json
├── package.json
├── tsconfig.json
└── tsconfig.build.json

И запустит npm install.

Запуск

cd my-app
npm run start:dev

Открыть http://localhost:3000 — увидишь Hello World!.

Скрипты

package.json:

{
    "scripts": {
        "build": "nest build",
        "start": "nest start",
        "start:dev": "nest start --watch",
        "start:debug": "nest start --debug --watch",
        "start:prod": "node dist/main",
        "test": "jest",
        "test:watch": "jest --watch",
        "test:cov": "jest --coverage",
        "test:e2e": "jest --config ./test/jest-e2e.json"
    }
}

Основные:

  • start:dev — с hot reload.
  • build — сборка в dist/.
  • start:prod — прод-запуск.
  • test — unit-тесты.

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('Сервер: http://localhost:3000');
}

bootstrap();

Разбор:

  • NestFactory.create — создать приложение.
  • AppModule — корневой модуль.
  • app.listen(3000) — запустить.

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 {}

Метаданные модуля:

  • imports — другие модули.
  • controllers — HTTP-контроллеры.
  • providers — сервисы.
  • exports — что отдавать наружу.

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();
    }
}

constructor — DI: NestJS сам подставит AppService.

app.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
    getHello(): string {
        return 'Hello World!';
    }
}

Первый роут

Добавим в контроллер:

@Get('users')
getUsers(): string[] {
    return ['Иван', 'Мария'];
}

Проверка:

curl http://localhost:3000/users
# ["Иван","Мария"]

Nest CLI команды

Создать модуль:

nest g module users

Создать контроллер:

nest g controller users

Создать сервис:

nest g service users

Создать всё сразу (CRUD):

nest g resource users

Что создаст resource:

src/users/
├── dto/
│   ├── create-user.dto.ts
│   └── update-user.dto.ts
├── entities/
│   └── user.entity.ts
├── users.controller.ts
├── users.module.ts
├── users.service.ts
└── users.service.spec.ts

И автоматически подключит в AppModule.

Структура проекта

Рекомендую:

src/
├── main.ts
├── app.module.ts
├── common/
│   ├── decorators/
│   ├── filters/
│   ├── guards/
│   ├── interceptors/
│   └── pipes/
├── config/
│   └── configuration.ts
├── modules/
│   ├── users/
│   │   ├── dto/
│   │   ├── entities/
│   │   ├── users.controller.ts
│   │   ├── users.module.ts
│   │   └── users.service.ts
│   ├── auth/
│   └── posts/
└── shared/
    └── services/

Каждая фича — модуль в modules/.

Запуск в watch-режиме

npm run start:dev

Что происходит:

  1. Компиляция TypeScript.
  2. Запуск сервера.
  3. Отслеживание изменений.
  4. Автоматическая перезагрузка.

Отладка в VS Code

.vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Debug NestJS",
            "runtimeExecutable": "npm",
            "runtimeArgs": ["run", "start:debug"],
            "port": 9229,
            "restart": true
        }
    ]
}

F5 — запуск с breakpoints.

Переменные окружения

.env:

NODE_ENV=development
PORT=3000
DATABASE_URL=postgres://...
JWT_SECRET=secret

src/main.ts:

const port = Number(process.env.PORT) || 3000;
await app.listen(port);

В NestJS обычно через @nestjs/config:

import { ConfigModule } from '@nestjs/config';

@Module({
    imports: [
        ConfigModule.forRoot({ isGlobal: true }),
    ],
})
export class AppModule {}

Чтение:

import { ConfigService } from '@nestjs/config';

constructor(private config: ConfigService) {
    const port = this.config.get<number>('PORT', 3000);
}

Практика: мини-API

nest g resource users — создаст всё.

Заменим users.service.ts:

import { Injectable } from '@nestjs/common';

export interface User {
    id: number;
    name: string;
    email: string;
}

@Injectable()
export class UsersService {
    private users: User[] = [
        { id: 1, name: 'Иван', email: 'ivan@example.com' },
    ];

    findAll(): User[] {
        return this.users;
    }

    findOne(id: number): User | undefined {
        return this.users.find(u => u.id === id);
    }

    create(user: Omit<User, 'id'>): User {
        const newUser = { id: this.users.length + 1, ...user };
        this.users.push(newUser);
        return newUser;
    }
}

Контроллер:

import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { UsersService, User } from './users.service';

@Controller('users')
export class UsersController {
    constructor(private readonly usersService: UsersService) {}

    @Get()
    findAll(): User[] {
        return this.usersService.findAll();
    }

    @Get(':id')
    findOne(@Param('id') id: string): User | undefined {
        return this.usersService.findOne(+id);
    }

    @Post()
    create(@Body() user: Omit<User, 'id'>): User {
        return this.usersService.create(user);
    }
}

Проверка

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":"maria@example.com"}'

Итог

  • nest new — создать проект.
  • start:dev — watch-режим.
  • CLI — генерирует модули, контроллеры, сервисы.
  • Структура: main.ts, app.module.ts, модули.
  • nest g resource — CRUD из коробки.
  • DI — через конструктор.
  • ConfigModule — для env.
  • VS Code — встроенный debug.

Дальше — модули.