Гид по технологиям

Создание CRUD REST API на Nest.js с TypeORM и PostgreSQL

6 min read Backend Обновлено 09 Jan 2026
CRUD REST API на Nest.js с TypeORM и PostgreSQL
CRUD REST API на Nest.js с TypeORM и PostgreSQL

Важное: все примеры предполагают, что у вас установлен Node.js и доступ к экземпляру PostgreSQL (локально или в облаке).

Ключевая идея

Nest.js — это фреймворк для Node.js, который даёт модульную, масштабируемую архитектуру и предлагает встроенную интеграцию с TypeORM. CRUD (create, read, update, delete) — основа любой REST API: модель (Entity), сервис (логика), контроллер (эндпоинты) и соединение с БД.

Введение

Редактор с JavaScript-кодом на фоне и логотипом Nest.js на переднем плане.

Как и другие фреймворки для Node.js, Nest.js предоставляет инструменты для построения надёжных и масштабируемых бэкенд-сервисов. Важная задача — грамотно реализовать CRUD-операции, чтобы API было простым, предсказуемым и тестируемым.

Что вы получите из этого руководства

  • Полный рабочий пример CRUD REST API на Nest.js с TypeORM и PostgreSQL.
  • Пошаговые команды для генерации модулей и файлов.
  • Контрольные списки для ролей (разработчик, DevOps, QA).
  • Критерии приёмки и набор тест-кейсов.
  • Практические советы по безопасности, миграции и отладке.

Начало работы с Nest.js

Установите CLI Nest.js глобально:

npm i -g @nestjs/cli

Создайте новый проект:

nest new crud-app

CLI предложит выбрать менеджер пакетов — используйте тот, который предпочитаете. В примерах ниже применяется npm.

Перейдите в директорию проекта и запустите сервер разработки:

cd crud-app
npm run start

CLI сгенерирует базовую структуру проекта с необходимыми конфигурациями.

Создание базы данных PostgreSQL

В примере используется облачная инстанция PostgreSQL, но допустима локальная установка на Windows, macOS или Linux.

Чтобы создать облачный экземпляр (пример — ElephantSQL):

  1. Перейдите на ElephantSQL, зарегистрируйтесь и откройте страницу своего аккаунта.

Главная страница сайта ElephantSQL

  1. Нажмите кнопку создания нового экземпляра и следуйте инструкциям.

Кнопка создания нового экземпляра PostgreSQL на платформе ElephantSQL

  1. Выберите тариф (есть бесплатный), укажите имя и регион.
  2. Перейдите в настройки экземпляра и скопируйте предоставленный DATABASE_URL.

Конфигурация соединения с базой данных

В корне проекта создайте файл .env и вставьте URL подключения:

DATABASE_URL=""

Установите необходимые пакеты:

npm install pg typeorm @nestjs/typeorm @nestjs/config

Создайте модуль базы данных через CLI:

nest g module database

Откройте файл database/database.module.ts и добавьте конфигурацию TypeORM:

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from '../users/models/user.entity';

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],

      useFactory: async (configService: ConfigService) => ({
        type: 'postgres',
        url: configService.get('DATABASE_URL'),
        entities: [User],
        synchronize: true
      }),
    }),
  ],
})

export class DatabaseModule {}

Пояснение: здесь TypeORM подключается к PostgreSQL по URL из .env и регистрирует сущность User. Параметр synchronize: true удобен в разработке, но в проде лучше использовать миграции.

Обновите AppModule

Добавьте DatabaseModule и конфигурацию окружения в app.module.ts:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './database/database.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: '.env',
    }),
    DatabaseModule,
  ],

  controllers: [AppController],
  providers: [AppService],
})

export class AppModule {}

Модуль users

Модуль users инкапсулирует логику CRUD для сущности User. Сгенерируйте модуль:

nest g module users

CLI добавит модуль в app.module.ts.

Создаём сущность User

TypeORM связывает классы-сущности с таблицами базы данных. Создайте файл users/models/user.entity.ts:

import { Entity, PrimaryGeneratedColumn, Column,  } from "typeorm";

@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @Column()
    email: string;
}

Коротко: id — первичный ключ, name и email — обычные колонки.

Сервис для CRUD

Сгенерируйте сервис:

nest g service users

Откройте users.service.ts (в исходнике был опечатка user-auth.service.ts) и вставьте код:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './models/user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository,
  ) {}

  async findAll(): Promise {
    return this.userRepository.find();
  }

  async findOne(id: number): Promise {
    return this.userRepository.findOne({ where: { id } });
  }

  async create(user: Partial): Promise {
    const newuser = this.userRepository.create(user);
    return this.userRepository.save(newuser);
  }

  async update(id: number, user: Partial): Promise {
    await this.userRepository.update(id, user);
    return this.userRepository.findOne({ where: { id } });
  }

  async delete(id: number): Promise {
    await this.userRepository.delete(id);
  }
}

Пояснение: сервис реализует стандартные операции: получить всех, получить по id, создать, обновить и удалить.

Совет: на этапе валидации и безопасности добавьте DTO и Pipes (class-validator) для строгой валидации входящих данных.

Контроллер API

Сгенерируйте контроллер:

nest g controller users

В users.controller.ts добавьте:

import { Controller, Get, Post, Body, Put, Param, Delete, NotFoundException, HttpCode } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './models/user.entity';

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

  @Get()
  async findAll(): Promise {
    return this.usersService.findAll();
  }

  @Post()
  @HttpCode(201)
  async create(@Body() user: User): Promise {
    const createdUser = await this.usersService.create(user);
    return createdUser;
  }

  @Put(':id')
  async update (@Param('id') id: number, @Body() user: User): Promise {
    await this.usersService.update(id, user);
    return { message: 'User updated successfully' };
  }

  @Delete(':id')
  async delete(@Param('id') id: number): Promise {
    const user = await this.usersService.findOne(id);

    if (!user) {
      throw new NotFoundException('User does not exist!');
    }

    await this.usersService.delete(id);
    return { message: 'User deleted successfully' };
  }
}

Контроллер связывает HTTP-запросы с сервисом. Рекомендуется добавить DTO для create/update и использовать Pipes для валидации.

Обновите users.module.ts

import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './models/user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService]
})

export class UsersModule {}

Тестирование CRUD локально

Запустите сервер:

npm run start

По умолчанию сервер стартует на порту 3000. Примеры запросов (curl):

  • Получить всех:
curl http://localhost:3000/api/users
  • Создать пользователя:
curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Ivan","email":"ivan@example.com"}'
  • Обновить пользователя:
curl -X PUT http://localhost:3000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"Ivan Petrov"}'
  • Удалить пользователя:
curl -X DELETE http://localhost:3000/api/users/1

Когда этот подход не подходит

  • Очень простое приложение, где накладные расходы Nest.js избыточны. В таких случаях можно использовать более лёгкий Express/Koa.
  • Высокопроизводительные сервисы с узкими требованиями к latency: иногда минималистичная настройка на чистом Node.js/Express даёт меньше абстракций.

Альтернативные подходы

  • Использовать MikroORM вместо TypeORM (альтернатива с иными фичами миграции).
  • Применять Prisma ORM для типобезопасных запросов и удобных миграций.
  • Для GraphQL API заменить контроллеры на резолверы и использовать @nestjs/graphql.

Проверка качества: критерии приёмки

  • API возвращает 200/201/204 корректные коды статуса.
  • При создании пользователя возвращается его объект с id.
  • При обновлении поля реально меняются в БД.
  • Удалённый пользователь больше не доступен через GET.
  • Валидация входных данных: email валиден, name не пуст.

Набор тест-кейсов (acceptance)

  1. Создать пользователя с валидными данными — ожидается 201 и объект пользователя.
  2. Создать пользователя с некорректным email — ожидается 400.
  3. Получить список пользователей — возвращается массив.
  4. Обновить существующего пользователя — возвращает сообщение об успешном обновлении и новые данные в БД.
  5. Удалить пользователя — при последующем GET по id возвращается 404.

Чек-листы по ролям

Разработчик

  • Написать DTO и валидацию.
  • Покрыть основные методы unit-тестами.
  • Настроить логи и обработчики ошибок.

DevOps

  • Настроить переменные окружения и секреты (не хранить DATABASE_URL в репозитории).
  • Подготовить миграции и pipeline деплоя.
  • Настроить мониторинг и бэкапы БД.

QA

  • Проверить сценарии создания/обновления/удаления.
  • Проверить валидацию и обработку ошибок.
  • Выполнить нагрузочное тестирование для ключевых сценариев.

Security hardening (основные меры)

  • Не используйте synchronize: true в проде — применяйте миграции.
  • Валидация входных данных (class-validator).
  • Ограничьте вывод ошибок в продакшене, не раскрывайте SQL-детали.
  • Храните секреты в безопасном хранилище (Vault/Secrets manager).
  • Включите HTTPS и настройте CORS только для доверенных доменов.

Миграции и совместимость

  • Для управления схемой используйте миграции TypeORM или инструменты упаковки миграций.
  • При изменении сущностей планируйте миграции, тесты и откатные сценарии.

Мини-методология разработки CRUD

  1. Описать модель данных (Entity).
  2. Создать DTO и правила валидации для входа.
  3. Реализовать сервис с чистой бизнес-логикой (без HTTP-зависимостей).
  4. Сделать контроллеры, которые переводят HTTP-запросы в вызовы сервиса.
  5. Покрыть критичные сценарии тестами и интеграционными тестами с тестовой БД.
  6. Подготовить миграции и план деплоя.

Decision flow (принятие решения использовать Nest.js)

flowchart TD
  A[Нужно масштабируемое приложение?] -->|Да| B[Использовать Nest.js]
  A -->|Нет| C[Рассмотрите Express/Koa]
  B --> D{Нужен ORM?}
  D -->|Да| E[TypeORM/Prisma/MikroORM]
  D -->|Нет| F[Используйте прямые SQL-клиенты]

Примеры и паттерны (советы)

  • DTO: используйте отдельные классы CreateUserDto и UpdateUserDto с class-validator.
  • Транзакции: для сложных операций используйте менеджер транзакций TypeORM.
  • Логирование: применяйте встроенный Logger Nest.js или сторонние службы (Sentry).

Отладка и распространённые ошибки

  • Ошибка соединения к БД: проверьте DATABASE_URL и сетевые правила.
  • Не найден репозиторий User: убедитесь, что сущность импортирована в TypeOrmModule.forFeature и в forRootAsync.
  • Проблемы с типами: при использовании JS в place of TS — поддержите правильные типы в runtime.

Роллбек и инцидентный план

  • Откатывайте миграции, если schema breaking.
  • При падении сервиса быстро откатывайте на предыдущий стабильный образ.
  • Имейте резервную копию БД перед крупными изменениями.

Краткая галерея крайних случаев

  • Множественные связи (relations): добавляйте отношения постепенно и тестируйте join-ы.
  • Большие payloads: используйте пагинацию и лимиты.
  • Масштабирование: выносите базу на отдельный кластер, используйте read replicas.

1-строчная глоссарий

  • Entity: класс, который отображается на таблицу БД.
  • DTO: объект передачи данных, описывает вход/выход API.
  • Repository: слой доступа к данным, инжектируемый TypeORM.

Заключение

Nest.js даёт структуру и проверенные паттерны, чтобы быстро строить и поддерживать CRUD API. Преимущество в модульности, тестируемости и готовых интеграциях с ORM. Для продакшна обращайте внимание на миграции, безопасность и наблюдаемость.

Краткий план следующего шага: добавить DTO и валидацию, покрыть сервисы unit-тестами и настроить миграции TypeORM перед развёртыванием.


Краткое резюме:

  • Разверните окружение и подключите БД через .env.
  • Опишите сущность, сервис и контроллер для CRUD.
  • Добавьте валидацию, миграции и меры безопасности перед продакшеном.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Push-уведомления в React с Firebase
Frontend

Push-уведомления в React с Firebase

Отправка событий в Vue: $emit и defineEmits
Frontend

Отправка событий в Vue: $emit и defineEmits

Режим обслуживания в Django
Django

Режим обслуживания в Django

Push‑уведомления в JavaScript
JavaScript

Push‑уведомления в JavaScript

Moment.js в React: управление датой и временем
React

Moment.js в React: управление датой и временем

Создать страницу 404 в React
Frontend

Создать страницу 404 в React