Микросервисы на TypeScript: архитектура и практика от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему TypeScript — идеальный выбор для микросервисов

Современная разработка backend-систем всё чаще отходит от монолитов в пользу микросервисной архитектуры. TypeScript, будучи строго типизированной надстройкой над JavaScript, предлагает уникальное сочетание гибкости и надёжности. Статическая типизация на этапе компиляции позволяет отлавливать ошибки интеграции между сервисами до того, как они попадут в продакшн, а богатая экосистема (NestJS, Express, Fastify) даёт готовые инструменты для построения распределённых систем.

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

1. Архитектура микросервисов на TypeScript: ключевые принципы

1.1 Декомпозиция предметной области

Первый шаг — разбиение бизнес-логики на независимые сервисы. Каждый микросервис отвечает за свою ограниченную область (Bounded Context). В TypeScript это естественным образом выражается через модули и пакеты.

Пример декомпозиции для интернет-магазина:

  • Auth Service — аутентификация и JWT-токены
  • Product Service — каталог товаров и цены
  • Order Service — оформление и история заказов
  • Payment Service — обработка платежей

Каждый сервис — это отдельное приложение на TypeScript со своим package.json, конфигурацией и точкой входа (main.ts).

1.2 Выбор технологического стека

Для быстрого старта рекомендуется использовать NestJS — фреймворк, из коробки поддерживающий микросервисные паттерны. Он предоставляет транспортные адаптеры для TCP, Redis, RabbitMQ, Kafka и gRPC.

Базовый стек:

  • Язык: TypeScript (строгий режим, strict: true)
  • Фреймворк: NestJS
  • Брокер сообщений: RabbitMQ (через @nestjs/microservices)
  • База данных: PostgreSQL (каждый сервис — свою БД)
  • Контейнеризация: Docker + Docker Compose

1.3 Паттерны взаимодействия

Различают два основных подхода: синхронный (HTTP/gRPC) и асинхронный (очереди). Для критичных по времени операций используйте синхронные запросы, для фоновых задач — очереди.

Пример настройки гибридного сервиса в NestJS:

// main.ts — точка входа микросервиса
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';

async function bootstrap() {
  // HTTP сервер для REST API
  const app = await NestFactory.create(AppModule);
  
  // Подключение RabbitMQ для асинхронного обмена
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.RMQ,
    options: {
      urls: ['amqp://localhost:5672'],
      queue: 'orders_queue',
      queueOptions: { durable: true },
    },
  });

  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();

2. Практическая реализация: от модели данных до API

2.1 Создание общего пакета с типами

Чтобы избежать дублирования интерфейсов между сервисами, вынесите общие типы в отдельный npm-пакет (например, @mycompany/shared-types). Это ключевое преимущество TypeScript — единый источник правды для всех сервисов.

// shared-types/src/dto/order.dto.ts
export interface CreateOrderDto {
  userId: string;
  productId: string;
  quantity: number;
  totalPrice: number;
}

export interface OrderResponse {
  id: string;
  status: 'pending' | 'confirmed' | 'cancelled';
  createdAt: Date;
}

2.2 Реализация Product Service (REST API)

Сервис каталога товаров. Используем TypeORM для работы с PostgreSQL и декораторы NestJS для валидации.

// product.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Product } from './product.entity';

@Injectable()
export class ProductService {
  constructor(
    @InjectRepository(Product)
    private productRepo: Repository<Product>,
  ) {}

  async getProduct(id: string): Promise<Product> {
    return this.productRepo.findOneBy({ id });
  }

  async createProduct(data: Partial<Product>): Promise<Product> {
    const product = this.productRepo.create(data);
    return this.productRepo.save(product);
  }
}

2.3 Асинхронное взаимодействие через RabbitMQ

При создании заказа Order Service отправляет событие в очередь, а инвентарный сервис его обрабатывает.

Отправка события (Order Service):

// order.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices';

@Controller('orders')
export class OrderController {
  private client: ClientProxy;

  constructor() {
    this.client = ClientProxyFactory.create({
      transport: Transport.RMQ,
      options: {
        urls: ['amqp://localhost:5672'],
        queue: 'inventory_queue',
      },
    });
  }

  @Post()
  async createOrder(@Body() createOrderDto: any) {
    // Сохраняем заказ в БД...
    // Отправляем событие в очередь
    this.client.emit('order_created', createOrderDto);
    return { status: 'processing' };
  }
}

Обработка события (Inventory Service):

// inventory.controller.ts
import { Controller } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';

@Controller()
export class InventoryController {
  @EventPattern('order_created')
  async handleOrderCreated(@Payload() data: any) {
    console.log('Резервируем товар:', data.productId);
    // Логика уменьшения остатков...
  }
}

3. Отказоустойчивость и мониторинг

3.1 Circuit Breaker и Retry

Для синхронных вызовов между сервисами используйте паттерн Circuit Breaker. В TypeScript это реализуется через библиотеку cockatiel или встроенные механизмы NestJS.

import { CircuitBreakerPolicy }                

Блоги

Рекомендаций по книгам