Разработка бэкенда сайта на Node.js (NestJS)

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка бэкенда сайта на Node.js (NestJS)
Сложная
от 1 недели до 3 месяцев
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка бэкенда сайта на Node.js (NestJS)

NestJS — это не просто фреймворк, это архитектурное решение. Он навязывает структуру, которую команда иначе изобретала бы сама: модули, провайдеры, dependency injection, декораторы. Для сложных проектов с несколькими разработчиками это ценность. Для небольшого API в одиночку — избыточность.

Выбор NestJS оправдан при: монорепо с несколькими приложениями, микросервисной архитектуре, команде от трёх разработчиков, долгосрочном проекте с меняющейся командой.

Структура модулей

Каждый функциональный блок — отдельный модуль. Модуль объявляет, что предоставляет наружу и что импортирует:

// users/users.module.ts
@Module({
  imports: [TypeOrmModule.forFeature([User]), JwtModule],
  controllers: [UsersController],
  providers: [UsersService, UsersRepository],
  exports: [UsersService]
})
export class UsersModule {}
// app.module.ts
@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync({
      useFactory: (config: ConfigService) => ({
        type: 'postgres',
        url: config.get('DATABASE_URL'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
        migrations: [__dirname + '/migrations/*{.ts,.js}'],
        synchronize: false
      }),
      inject: [ConfigService]
    }),
    UsersModule,
    ProductsModule,
    AuthModule,
    OrdersModule,
  ]
})
export class AppModule {}

Контроллеры и валидация

Контроллер отвечает только за HTTP-слой: маршруты, заголовки, статус-коды. Логика — в сервисах.

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

  @Get()
  @Roles('admin')
  findAll(@Query() paginationDto: PaginationDto): Promise<PaginatedResult<User>> {
    return this.usersService.findAll(paginationDto)
  }

  @Get(':id')
  @ApiParam({ name: 'id', type: 'number' })
  async findOne(@Param('id', ParseIntPipe) id: number): Promise<User> {
    const user = await this.usersService.findById(id)
    if (!user) throw new NotFoundException(`User ${id} not found`)
    return user
  }

  @Post()
  @HttpCode(HttpStatus.CREATED)
  create(@Body() createUserDto: CreateUserDto): Promise<User> {
    return this.usersService.create(createUserDto)
  }

  @Patch(':id')
  update(
    @Param('id', ParseIntPipe) id: number,
    @Body() updateUserDto: UpdateUserDto
  ): Promise<User> {
    return this.usersService.update(id, updateUserDto)
  }
}

Валидация через class-validator + ValidationPipe:

export class CreateUserDto {
  @IsEmail()
  @Transform(({ value }) => value.toLowerCase().trim())
  email: string

  @IsString()
  @MinLength(8)
  @Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, {
    message: 'Пароль должен содержать заглавные, строчные буквы и цифры'
  })
  password: string

  @IsOptional()
  @IsString()
  @MaxLength(100)
  name?: string
}

ValidationPipe с whitelist: true автоматически обрезает все поля, не объявленные в DTO — это защита от массового присвоения.

ORM: TypeORM vs Prisma vs MikroORM

NestJS официально поддерживает TypeORM, Prisma, MikroORM, Mongoose. Сравнение для PostgreSQL-проектов:

TypeORM Prisma MikroORM
Migrations Встроенные Встроенные Встроенные
Типизация Через декораторы Генерируется из схемы Unit of Work паттерн
Слабые стороны Медленный при сложных JOIN Генерация типов, доп. зависимость Кривая обучения
Production-ready Да Да Да

TypeORM entity:

@Entity('products')
@Index(['slug'], { unique: true })
export class Product {
  @PrimaryGeneratedColumn()
  id: number

  @Column({ length: 255 })
  name: string

  @Column({ unique: true, length: 255 })
  slug: string

  @Column('decimal', { precision: 10, scale: 2 })
  price: number

  @Column({ type: 'jsonb', nullable: true })
  attributes: Record<string, unknown>

  @ManyToOne(() => Category, (category) => category.products, { onDelete: 'SET NULL' })
  @JoinColumn({ name: 'category_id' })
  category: Category

  @CreateDateColumn({ name: 'created_at' })
  createdAt: Date

  @UpdateDateColumn({ name: 'updated_at' })
  updatedAt: Date
}

Аутентификация

Паттерн: JWT access token (15 мин) + refresh token (30 дней) в httpOnly cookie.

@Injectable()
export class AuthService {
  constructor(
    private usersService: UsersService,
    private jwtService: JwtService,
    private configService: ConfigService
  ) {}

  async login(user: User): Promise<{ accessToken: string; refreshToken: string }> {
    const payload = { sub: user.id, email: user.email, role: user.role }

    const [accessToken, refreshToken] = await Promise.all([
      this.jwtService.signAsync(payload, {
        secret: this.configService.get('JWT_SECRET'),
        expiresIn: '15m'
      }),
      this.jwtService.signAsync({ sub: user.id }, {
        secret: this.configService.get('JWT_REFRESH_SECRET'),
        expiresIn: '30d'
      })
    ])

    await this.usersService.saveRefreshToken(user.id, refreshToken)
    return { accessToken, refreshToken }
  }
}

Очереди и фоновые задачи

@nestjs/bull (Bull + Redis) для async-задач:

@Processor('email')
export class EmailProcessor {
  @Process('welcome')
  async sendWelcomeEmail(job: Job<{ userId: number }>): Promise<void> {
    const user = await this.usersService.findById(job.data.userId)
    await this.mailerService.send({
      to: user.email,
      subject: 'Добро пожаловать',
      template: 'welcome',
      context: { name: user.name }
    })
  }

  @Process('order-confirmation')
  @OnQueueFailed()
  async handleFailure(job: Job, error: Error): Promise<void> {
    this.logger.error(`Job ${job.id} failed: ${error.message}`)
    // алерт в Sentry/Telegram
  }
}

Микросервисы

NestJS нативно поддерживает микросервисную архитектуру через транспортные слои:

// main.ts для микросервиса
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
  transport: Transport.RMQ,
  options: {
    urls: [process.env.RABBITMQ_URL],
    queue: 'orders_queue',
    queueOptions: { durable: true }
  }
})

// Обработчик сообщений
@MessagePattern('create_order')
async createOrder(@Payload() data: CreateOrderDto, @Ctx() context: RmqContext) {
  const channel = context.getChannelRef()
  const originalMsg = context.getMessage()
  try {
    const order = await this.ordersService.create(data)
    channel.ack(originalMsg)
    return order
  } catch (err) {
    channel.nack(originalMsg, false, false)
    throw err
  }
}

OpenAPI документация

Swagger генерируется из декораторов и DTO без дополнительных схем:

// main.ts
const config = new DocumentBuilder()
  .setTitle('API')
  .setVersion('1.0')
  .addBearerAuth()
  .build()

const document = SwaggerModule.createDocument(app, config, {
  operationIdFactory: (controllerKey, methodKey) => methodKey
})
SwaggerModule.setup('api/docs', app, document)

Тестирование

NestJS включает тестовые утилиты из коробки:

describe('UsersService', () => {
  let service: UsersService

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService,
        { provide: getRepositoryToken(User), useValue: mockRepository }
      ]
    }).compile()

    service = module.get<UsersService>(UsersService)
  })

  it('should throw NotFoundException when user not found', async () => {
    mockRepository.findOne.mockResolvedValue(null)
    await expect(service.findById(999)).rejects.toThrow(NotFoundException)
  })
})

Сроки разработки

NestJS-проект требует больше времени на старте из-за структуры, но экономит на поддержке:

  • Архитектура и проектирование модулей — 1 неделя: схема БД, модули, DTO, API-контракт
  • Базовый каркас + auth — 1–1,5 недели
  • Модули бизнес-логики — 2–4 недели в зависимости от числа сущностей
  • Интеграции, очереди, файлы — 1–3 недели
  • Тесты (unit + e2e) — 1–2 недели
  • Документация Swagger + DevOps — 3–5 дней

Средний корпоративный сайт или веб-приложение: 6–12 недель. Монорепо с несколькими сервисами — от 3 месяцев. NestJS окупает вложения на проектах, которые живут дольше года и меняют команду.