☰ Mục lục series
Tài liệu NestJS tiếng Việt
  1. Nhập môn (Overview)
    1. Giới thiệu
    2. First steps
    3. Controllers
    4. Providers
    5. Modules
    6. Middleware
    7. Exception filters
    8. Pipes
    9. Guards
    10. Interceptors
    11. Custom decorators
  2. Nền tảng (Fundamentals)
    1. Custom providers
    2. Asynchronous providers
    3. Dynamic modules
    4. Injection scopes
    5. Circular dependency
    6. Module reference
    7. Lazy-loading modules
    8. Execution context
    9. Lifecycle events
    10. Discovery service
    11. Platform agnosticism
    12. Testing
  3. Kỹ thuật (Techniques)
    1. Configuration
    2. Database (SQL)
    3. MongoDB
    4. Validation
    5. Caching
    6. Serialization
    7. Versioning
    8. Task scheduling
    9. Queues
    10. Logging
    11. Cookies
    12. Events
    13. Compression
    14. File upload
    15. Streaming files
    16. HTTP module
    17. Session
    18. MVC
    19. Performance (Fastify)
    20. Server-Sent Events
  4. Bảo mật (Security)
    1. Authentication
    2. Authorization
    3. Encryption & Hashing
    4. Helmet
    5. CORS
    6. CSRF
    7. Rate limiting
    8. Vòng đời request
  5. OpenAPI (Swagger)
    1. Introduction
    2. Types and parameters
    3. Operations
    4. Security
    5. Mapped types
    6. Decorators
    7. CLI plugin
    8. Other features
  6. Recipes
    1. REPL
    2. CRUD generator
    3. SWC (fast compiler)
    4. Passport (auth)
    5. Hot reload
    6. MikroORM
    7. Router module
    8. Health checks (Terminus)
    9. CQRS
    10. Prisma
    11. Serve static
    12. Commander
    13. Async local storage
  7. WebSockets
    1. Gateways
    2. Exception filters
    3. Pipes
    4. Guards
    5. Interceptors
    6. Adapters
  8. Microservices
    1. Overview
    2. Redis
    3. MQTT
    4. NATS
    5. RabbitMQ
    6. Kafka
    7. gRPC
    8. Custom transporters
    9. Exception filters
    10. Pipes
    11. Pre-request hooks
    12. Guards
    13. Interceptors
  9. GraphQL
    1. Quick start
    2. Resolvers
    3. Mutations
    4. Subscriptions
    5. Scalars
    6. Directives
    7. Interfaces
    8. Unions and enums
    9. Field middleware
    10. Mapped types
    11. Plugins
    12. Complexity
    13. Extensions
    14. CLI plugin
    15. Generating SDL
    16. Sharing models
    17. Other features
    18. Federation
  10. CLI & triển khai
    1. CLI overview
    2. Workspaces
    3. Libraries
    4. Usage
    5. Scripts
    6. Deployment
    7. Standalone apps
  11. FAQ
    1. Serverless
    2. HTTP adapter
    3. Keep-Alive connections
    4. Global path prefix
    5. Raw body
    6. Hybrid application
    7. HTTPS & multiple servers
    8. Common errors
  12. Phụ lục
    1. Bảng thuật ngữ
Microservices

MQTT

Bản dịch từ docs.nestjs.com/microservices/mqtt

MQTT (Message Queuing Telemetry Transport) là một messaging protocol mã nguồn mở, nhẹ, được tối ưu cho độ trễ thấp. Protocol này cung cấp một cách kết nối thiết bị vừa có khả năng mở rộng vừa tiết kiệm chi phí, dựa trên mô hình publish/subscribe. Một hệ thống giao tiếp xây dựng trên MQTT gồm publishing server, một broker và một hoặc nhiều client. Nó được thiết kế cho các thiết bị bị giới hạn tài nguyên và các network có băng thông thấp, độ trễ cao hoặc không ổn định.

Installation (cài đặt)

Để bắt đầu xây dựng microservice dựa trên MQTT, trước tiên hãy cài package cần thiết:

$ npm i --save mqtt

Overview (tổng quan)

Để sử dụng MQTT transporter, truyền object options sau vào method createMicroservice():

const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
  transport: Transport.MQTT,
  options: {
    url: 'mqtt://localhost:1883',
  },
});
const app = await NestFactory.createMicroservice(AppModule, {
  transport: Transport.MQTT,
  options: {
    url: 'mqtt://localhost:1883',
  },
});

Gợi ý Enum Transport được import từ package @nestjs/microservices.

Options (các option)

Object options phụ thuộc vào transporter được chọn. Transporter MQTT cung cấp các property được mô tả tại đây.

Client

Giống như các transporter khác của microservice, bạn có nhiều cách để tạo instance ClientProxy cho MQTT.

Một cách để tạo instance là dùng ClientsModule. Để tạo client instance với ClientsModule, import nó và dùng method register() để truyền một object options với các property giống như đã trình bày ở method createMicroservice() phía trên, cùng với property name dùng làm injection token. Đọc thêm về ClientsModule tại đây.

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'MATH_SERVICE',
        transport: Transport.MQTT,
        options: {
          url: 'mqtt://localhost:1883',
        }
      },
    ]),
  ]
  ...
})

Bạn cũng có thể dùng các cách khác để tạo client (ClientProxyFactory hoặc @Client()). Đọc thêm về chúng tại đây.

Context (ngữ cảnh)

Trong các tình huống phức tạp hơn, bạn có thể cần truy cập thêm thông tin về request đến. Khi dùng MQTT transporter, bạn có thể truy cập object MqttContext.

@MessagePattern('notifications')
getNotifications(@Payload() data: number[], @Ctx() context: MqttContext) {
  console.log(`Topic: ${context.getTopic()}`);
}
@Bind(Payload(), Ctx())
@MessagePattern('notifications')
getNotifications(data, context) {
  console.log(`Topic: ${context.getTopic()}`);
}

Gợi ý @Payload(), @Ctx() và MqttContext được import từ package @nestjs/microservices.

Để truy cập packet gốc của mqtt, dùng method getPacket() của object MqttContext, như sau:

@MessagePattern('notifications')
getNotifications(@Payload() data: number[], @Ctx() context: MqttContext) {
  console.log(context.getPacket());
}
@Bind(Payload(), Ctx())
@MessagePattern('notifications')
getNotifications(data, context) {
  console.log(context.getPacket());
}

Wildcards (ký tự đại diện)

Một subscription có thể trỏ tới một topic cụ thể, hoặc có thể chứa wildcard. Có hai loại wildcard: + và #. + là wildcard cho một cấp (single-level), còn # là wildcard cho nhiều cấp (multi-level), bao trùm nhiều cấp topic.

@MessagePattern('sensors/+/temperature/+')
getTemperature(@Ctx() context: MqttContext) {
  console.log(`Topic: ${context.getTopic()}`);
}
@Bind(Ctx())
@MessagePattern('sensors/+/temperature/+')
getTemperature(context) {
  console.log(`Topic: ${context.getTopic()}`);
}

Ghi chú người dịch Cách phân cấp topic bằng dấu / cùng wildcard +/# khá giống route param trong Express (/sensors/:id/temperature) hoặc router group trong Laravel, nhưng khác biệt quan trọng: MQTT không “bind” giá trị wildcard vào biến như route param — bạn chỉ nhận được toàn bộ topic qua context.getTopic() và phải tự parse ra phần mình cần.

Quality of Service (QoS)

Mọi subscription được tạo bằng decorator @MessagePattern hoặc @EventPattern sẽ subscribe với QoS 0. Nếu cần QoS cao hơn, bạn có thể đặt ở mức global bằng block subscribeOptions khi thiết lập kết nối, như sau:

const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
  transport: Transport.MQTT,
  options: {
    url: 'mqtt://localhost:1883',
    subscribeOptions: {
      qos: 2
    },
  },
});
const app = await NestFactory.createMicroservice(AppModule, {
  transport: Transport.MQTT,
  options: {
    url: 'mqtt://localhost:1883',
    subscribeOptions: {
      qos: 2
    },
  },
});

Per-pattern QoS (QoS theo từng pattern)

Bạn có thể override QoS của subscription MQTT theo từng pattern riêng, bằng cách cung cấp qos trong field extras của decorator pattern. Khi không được chỉ định, subscribeOptions.qos ở mức global sẽ được dùng làm giá trị mặc định.

@EventPattern('critical-events', { extras: { qos: 2 } })
handleCriticalEvent(@Payload() data: any) {
  // This subscription uses QoS 2
}

@EventPattern('metrics', { extras: { qos: 0 } })
handleMetrics(@Payload() data: any) {
  // This subscription uses QoS 0
}
@Bind(Payload())
@EventPattern('critical-events', { extras: { qos: 2 } })
handleCriticalEvent(data) {
  // This subscription uses QoS 2
}

@Bind(Payload())
@EventPattern('metrics', { extras: { qos: 0 } })
handleMetrics(data) {
  // This subscription uses QoS 0
}

Gợi ý Cấu hình QoS theo từng pattern không ảnh hưởng tới hành vi hiện có. Khi extras.qos không được chỉ định, subscription sẽ dùng giá trị subscribeOptions.qos ở mức global.

Record builders (bộ dựng record)

Để cấu hình các option của message (điều chỉnh mức QoS, đặt flag Retain hoặc DUP, hoặc thêm property vào payload), bạn có thể dùng class MqttRecordBuilder. Ví dụ, để đặt QoS thành 2, dùng method setQoS như sau:

const userProperties = { 'x-version': '1.0.0' };
const record = new MqttRecordBuilder(':cat:')
  .setProperties({ userProperties })
  .setQoS(1)
  .build();
client.send('replace-emoji', record).subscribe(...);

Gợi ý Class MqttRecordBuilder được export từ package @nestjs/microservices.

Và bạn cũng có thể đọc các option này ở phía server, bằng cách truy cập MqttContext.

@MessagePattern('replace-emoji')
replaceEmoji(@Payload() data: string, @Ctx() context: MqttContext): string {
  const { properties: { userProperties } } = context.getPacket();
  return userProperties['x-version'] === '1.0.0' ? '🐱' : '🐈';
}
@Bind(Payload(), Ctx())
@MessagePattern('replace-emoji')
replaceEmoji(data, context) {
  const { properties: { userProperties } } = context.getPacket();
  return userProperties['x-version'] === '1.0.0' ? '🐱' : '🐈';
}

Trong một số trường hợp bạn có thể muốn cấu hình user properties cho nhiều request, bạn có thể truyền các option này vào ClientProxyFactory.

import { Module } from '@nestjs/common';
import { ClientProxyFactory, Transport } from '@nestjs/microservices';

@Module({
  providers: [
    {
      provide: 'API_v1',
      useFactory: () =>
        ClientProxyFactory.create({
          transport: Transport.MQTT,
          options: {
            url: 'mqtt://localhost:1833',
            userProperties: { 'x-version': '1.0.0' },
          },
        }),
    },
  ],
})
export class ApiModule {}

Instance status updates (cập nhật trạng thái instance)

Để nhận cập nhật theo thời gian thực về kết nối và trạng thái của driver instance bên dưới, bạn có thể subscribe vào stream status. Stream này cung cấp các cập nhật trạng thái riêng cho driver đang dùng. Với driver MQTT, stream status phát ra các event connected, disconnected, reconnecting, và closed.

this.client.status.subscribe((status: MqttStatus) => {
  console.log(status);
});

Gợi ý Type MqttStatus được import từ package @nestjs/microservices.

Tương tự, bạn có thể subscribe vào stream status của server để nhận thông báo về trạng thái của server.

const server = app.connectMicroservice<MicroserviceOptions>(...);
server.status.subscribe((status: MqttStatus) => {
  console.log(status);
});

Listening to MQTT events (lắng nghe event của MQTT)

Trong một số trường hợp, bạn có thể muốn lắng nghe các event nội bộ được microservice phát ra. Ví dụ, bạn có thể lắng nghe event error để thực hiện thêm các xử lý khác khi có lỗi xảy ra. Để làm điều này, dùng method on(), như sau:

this.client.on('error', (err) => {
  console.error(err);
});

Tương tự, bạn có thể lắng nghe các event nội bộ của server:

server.on<MqttEvents>('error', (err) => {
  console.error(err);
});

Gợi ý Type MqttEvents được import từ package @nestjs/microservices.

Underlying driver access (truy cập driver bên dưới)

Với các use case phức tạp hơn, bạn có thể cần truy cập trực tiếp underlying driver instance. Điều này hữu ích cho các tình huống như tự đóng kết nối bằng tay hoặc dùng các method riêng của driver. Tuy nhiên, hãy nhớ rằng trong hầu hết trường hợp, bạn không cần truy cập trực tiếp driver.

Để làm điều này, bạn dùng method unwrap(), trả về underlying driver instance. Generic type parameter nên chỉ rõ loại driver instance bạn mong muốn.

const mqttClient = this.client.unwrap<import('mqtt').MqttClient>();

Tương tự, bạn có thể truy cập underlying driver instance của server:

const mqttClient = server.unwrap<import('mqtt').MqttClient>();

Nội dung gốc: NestJS Documentation © Kamil Myśliwiec, giấy phép MIT. Bản dịch và ghi chú: Lê Văn Dũng.