Интеграция TypeORM с NestJS: пошаговое руководство

Кратко
TypeORM позволяет работать с базой данных в объектно-ориентированном стиле, а NestJS предоставляет удобный каркас для интеграции. В этой статье показано, как установить зависимости, создать сущность, подключить базу (на примере SQLite), получить репозиторий и инжектировать его в сервис. Также добавлены рекомендации по безопасности, миграциям и чек-листы для разработчиков и операторов.
Что такое TypeORM и зачем он нужен
TypeORM — это ORM для TypeScript/JavaScript, реализующая отображение объектов в реляционные таблицы. Он упрощает создание запросов и управление схемой через сущности (entity). NestJS имеет официальную поддержку TypeORM через пакет @nestjs/typeorm, что ускоряет интеграцию.
Краткое определение: ORM — библиотека, которая позволяет писать операции с базой в терминах классов и объектов вместо ручного SQL.
Кому будет полезно
- Backend-разработчикам, использующим NestJS.
- Инженерам, которые хотят минимизировать шаблонный SQL-код.
- Командам, которым нужен единый подход к миграциям и репозиториям.
Быстрая карта маршрута
- Установить зависимости. 2. Создать сущность (entity). 3. Подключить TypeORM в модуле приложения. 4. Зарегистрировать сущность в модуле через forFeature. 5. Инжектировать репозиторий в сервис. 6. По желанию — использовать QueryBuilder и миграции.
Установка зависимостей
Используйте npm или yarn. Ниже — команды для npm.
npm install @nestjs/typeorm typeormДля SQLite (простая безсерверная БД, удобна для разработки):
npm install sqlite3Примечание: в реальном проекте для продакшн чаще используют PostgreSQL или MySQL. Для них понадобятся соответствующие драйверы (pg, mysql2).
Создание сущности
Сущность (entity) — класс с набором полей, который TypeORM использует для создания таблицы и маппинга данных.
Шаги создания сущности:
- Создайте файл в соответствии с конвенцией NestJS:
.entity.ts. - Импортируйте декораторы Entity, Column, PrimaryGeneratedColumn из typeorm.
- Экспортируйте класс и аннотируйте его декоратором @Entity().
- Для первичного ключа используйте @PrimaryGeneratedColumn(), остальные поля — @Column().
Пример файла сущности:
// src/test/test.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Test {
@PrimaryGeneratedColumn()
id: number;
@Column()
property_1: string;
@Column()
property_2: string;
@Column()
property_3: string;
}Результат в базе (примерная структура таблицы):
| Поле | Тип | Дополнительно |
|---|---|---|
| id | int | PRIMARY KEY AUTO_INCREMENT / AUTOINCREMENT |
| property_1 | varchar(255) | |
| property_2 | varchar(255) | |
| property_3 | varchar(255) |
Совет: явно указывайте длину и параметры колонок для контроля схемы, например @Column({ length: 100, nullable: false }).
Подключение приложения к базе данных
Включите TypeOrmModule в корневом модуле приложения (обычно app.module.ts). Для передачи конфигурации используйте TypeOrmModule.forRoot().
Основные шаги:
- Импортируйте TypeOrmModule из @nestjs/typeorm.
- Импортируйте все сущности, которые хотите синхронизировать.
- В массиве imports вызовите TypeOrmModule.forRoot({ …config }).
Пример конфигурации для SQLite (dev):
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Test } from './test/test.entity';
import { Entity2 } from './entity/entity.entity';
import { TestModule } from './test/test.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: 'test.db',
entities: [Test, Entity2],
synchronize: true, // Только для разработки
}),
TestModule,
],
controllers: [],
providers: [],
})
export class AppModule {}Important: не устанавливайте synchronize: true в production — это риск потери данных. Для production используйте миграции.
Создание репозитория
Репозиторий представляет доступ к данным сущности: find, save, delete и т. д. В NestJS вы регистрируете сущность в модуле через TypeOrmModule.forFeature, и TypeORM автоматически создаёт репозиторий.
Пример модуля, где регистрируется сущность Test:
// src/test/test.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TestController } from './test.controller';
import { TestService } from './test.service';
import { Test } from './test.entity';
@Module({
imports: [TypeOrmModule.forFeature([Test])],
providers: [TestService],
controllers: [TestController],
})
export class TestModule {}Инъекция репозитория в сервис через Dependency Injection
Инъекция зависимостей упрощает управление зависимостями и делает код тестируемым.
Шаги:
- Импортируйте Repository из typeorm и InjectRepository из @nestjs/typeorm.
- В конструкторе сервиса инжектируйте репозиторий с @InjectRepository(YourEntity).
Пример:
// test.service.ts
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Test } from './test.entity';
@Injectable()
export class TestService {
constructor(
@InjectRepository(Test)
private repo: Repository,
) {}
// Примеры методов
findAll() {
return this.repo.find();
}
create(data: Partial) {
const entity = this.repo.create(data);
return this.repo.save(entity);
}
} Запросы SQL с помощью TypeORM
Простые операции можно выполнять методами репозитория: find, findOne, save, remove, delete и т. д. Для сложных запросов используйте QueryBuilder.
Пример простого запроса:
this.repo.find({ where: { property_1: 'value' }, take: 10 });Пример QueryBuilder:
const users = await this.repo
.createQueryBuilder('test')
.where('test.property_1 = :val', { val: 'value' })
.orderBy('test.id', 'DESC')
.getMany();QueryBuilder удобен для динамических запросов и сложных джоинов.
Проверки качества и критерии приёмки
Критерии приёмки для базовой интеграции:
- Приложение стартует без ошибок и подключается к БД.
- Сущность создала ожидаемую таблицу (или миграцию) с правильными типами колонок.
- CRUD-эндпойнты работают корректно и возвращают ожидаемые данные.
- synchronize: false в production и миграции применяются корректно.
Тесты, которые полезно добавить:
- Unit-тесты для сервисов с моком репозитория.
- Интеграционные тесты, которые подняли бы тестовую БД (например, SQLite in-memory) и покрывают CRUD.
Чек-листы по ролям
Разработчик:
- Создать и документировать entity.
- Добавить entity в модуль через forFeature.
- Написать unit-тесты для сервисов с моками.
DevOps / Системный инженер:
- Переключить synchronize на false в production.
- Настроить миграции и CI/CD для их применения.
- Защитить доступ к БД (пароли в переменных окружения, SSL, firewall).
Код-ревьювер:
- Проверить, что сущности не содержат чувствительных данных в явном виде.
- Оценить использование транзакций в критичных операциях.
Рекомендации по безопасности и соответствию требованиям приватности
- Никогда не используйте synchronize: true в production — это может привести к потере данных.
- Храните параметры подключения в переменных окружения, а не в коде.
- Для удалённых баз используйте шифрование канала (TLS/SSL).
- Ограничьте права пользователя БД до минимально необходимых (least privilege).
- Для GDPR/локальных законов о защите данных документируйте, какие таблицы и поля содержат персональные данные и как они защищаются.
Миграции и работа с production
Для production используйте миграции вместо synchronize. TypeORM поддерживает генерацию миграций и их выполнение из CLI.
Подход:
- Используйте команду для генерации миграции (при использовании TypeORM CLI или альтернативных инструментов).
- Храните миграции в системе контроля версий.
- Автоматически применяйте миграции в CI/CD перед релизом.
Совет по переходу с SQLite на PostgreSQL:
- Проверьте совместимость типов колонок.
- Замените драйвер и обновите конфигурацию TypeOrmModule.forRoot.
- Создайте миграцию, которая приведёт схему в соответствие с новой СУБД.
Советы и распространённые ошибки
Когда это может не работать:
- Если entity не добавлена в массив entities в forRoot — таблица не будет создана.
- Ошибки типов при переходе между СУБД (например, SQLite vs PostgreSQL).
- Отсутствующие миграции при production-развёртывании.
Как избежать:
- Всегда регистрируйте entity в модулях и в конфигурации TypeORM.
- Используйте DTO и валидацию на уровне контроллера, чтобы не записывать неконсистентные данные в БД.
Короткая шпаргалка (cheat sheet)
Команды установки:
- npm install @nestjs/typeorm typeorm
- npm install sqlite3 (dev)
Типичная конфигурация forRoot:
TypeOrmModule.forRoot({
type: 'postgres', // или 'sqlite', 'mysql'
host: process.env.DB_HOST,
port: +process.env.DB_PORT,
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: process.env.DB_NAME,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: false,
})Инъекция репозитория:
constructor(@InjectRepository(Entity) private repo: Repository) {} Совместимость и замена технологий
Краткая матрица совместимости:
| TypeORM поддерживает | Примечание |
|---|---|
| SQLite | Отлично для разработки и тестов |
| PostgreSQL | Рекомендуется для production |
| MySQL / MariaDB | Поддерживается |
| MongoDB | Есть поддержка, но особенности реализаций отличаются |
Если планируете масштабировать — выбирайте PostgreSQL или другую полноценную СУБД, а не файловую SQLite.
Краткий глоссарий
- Entity: класс, который маппится на таблицу.
- Repository: слой доступа к данным конкретной сущности.
- synchronize: настройка, автоматически обновляющая схему БД.
- QueryBuilder: API для составления сложных SQL-запросов.
Итог
TypeORM и NestJS вместе дают мощный и удобный стек для работы с базами данных в TypeScript-проектах. Для разработки удобно использовать SQLite, но для продакшна предпочтительнее PostgreSQL с управляемыми миграциями и безопасной конфигурацией. Следуйте чек-листам, храните секреты в окружении и не используйте автоматическую синхронизацию схемы в проде.
Полезные ссылки
- Документация TypeORM — подробно описывает сущности, репозитории и QueryBuilder.
- Документация NestJS по модулю TypeORM — примеры интеграции и лучшие практики.
Похожие материалы
AutoHotkey: скрипты и как создавать свои
Ошибка Sync is Paused в Microsoft Edge — как исправить
Голосовой чат в Telegram: как запустить и управлять
Резервное копирование фото на Android — как и где хранить
Как скрыть полное имя в Slack