Giới thiệu

Trong môi trường phát triển phần mềm hiện đại, việc xây dựng một hệ thống microservice có khả năng mở rộng, bảo trì và tích hợp AI một cách hiệu quả đòi hỏi sự chuẩn hoá từ thiết kế API, schema dữ liệu cho tới quản lý state phía client. Bài viết sẽ hướng dẫn chi tiết cách thực hiện ba bước quan trọng: định nghĩa API contract bằng OpenAPI, thiết kế schema với TypeORM, và quản lý state trong React bằng Zustand, đồng thời tích hợp RabbitMQ để xử lý các tác vụ nặng.

1. Định nghĩa API contract với OpenAPI

API contract là bản mô tả chi tiết các endpoint, request/response và quy tắc xác thực. Sử dụng OpenAPI 3.0 giúp các service tự động sinh client SDK và tài liệu.

1.1 Tạo file openapi.yaml

openapi: 3.0.0
info:
  title: User Service API
  version: 1.0.0
paths:
  /users:
    get:
      summary: Lấy danh sách người dùng
      responses:
        '200':
          description: Thành công
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email

Sau khi có file openapi.yaml, có thể dùng swagger-cli để validate và openapi-generator để tạo SDK TypeScript.

2. Thiết kế Database Schema với TypeORM

TypeORM là ORM mạnh mẽ cho TypeScript, hỗ trợ migration và validation schema. Dưới đây là cách định nghĩa entity User và tạo migration.

2.1 Entity User

import { Entity, PrimaryGeneratedColumn, Column, Unique } from 'typeorm';

@Entity('users')
@Unique(['email'])
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 100 })
  name: string;

  @Column()
  email: string;
}

2.2 Tạo migration

npx typeorm migration:generate -n CreateUserTable
npx typeorm migration:run

Một migration sẽ tạo bảng users với ràng buộc duy nhất cho cột email, giúp tránh dữ liệu trùng lặp khi AI sinh code.

3. Quản lý state trong React với Zustand

Trong kiến trúc frontend, việc tách biệt state logic ra khỏi component giúp giảm độ phức tạp và tăng khả năng tái sử dụng. Zustand là một thư viện nhẹ, không cần Provider, phù hợp cho các dự án Next.js hoặc Vite.

3.1 Định nghĩa store

import create from 'zustand';
import { devtools } from 'zustand/middleware';

interface UserState {
  users: User[];
  fetchUsers: () => Promise;
}

export const useUserStore = create()(
  devtools(set => ({
    users: [],
    async fetchUsers() {
      const res = await fetch('/api/users');
      const data = await res.json();
      set({ users: data });
    },
  }))
);

Sử dụng trong component:

import { useEffect } from 'react';
import { useUserStore } from '@/store/user';

export default function UserList() {
  const { users, fetchUsers } = useUserStore();

  useEffect(() => {
    fetchUsers();
  }, []);

  return (
    <ul>
      {users.map(u => (
        <li key={u.id}>{u.name} - {u.email}</li>
      ))}
    </ul>
  );
}

4. Tích hợp RabbitMQ cho các tác vụ bất đồng bộ

Đối với các công việc nặng như xử lý ảnh, gửi email hoặc chạy mô hình AI, nên đưa chúng vào hàng đợi. RabbitMQ là lựa chọn phổ biến, dễ cấu hình và tương thích với Node.js.

4.1 Cài đặt và khởi động RabbitMQ

docker run -d --hostname my-rabbit --name rabbitmq \
  -p 5672:5672 -p 15672:15672 rabbitmq:3-management

4.2 Producer trong NestJS

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

@Injectable()
export class QueueService {
  private client: ClientProxy;

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

  async sendTask(payload: any) {
    await this.client.emit('task_created', payload).toPromise();
  }
}

4.3 Consumer

import { Controller } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';

@Controller()
export class TaskConsumer {
  @EventPattern('task_created')
  async handleTask(@Payload() data: any) {
    // Xử lý công việc nặng ở đây, ví dụ gọi AI model
    console.log('Received task:', data);
  }
}

Với kiến trúc trên, mỗi service chỉ chịu trách nhiệm một phần: API contract định nghĩa giao tiếp, schema đảm bảo dữ liệu nhất quán, Zustand quản lý UI state, và RabbitMQ xử lý công việc bất đồng bộ.

Kết luận

Áp dụng các nguyên tắc trên sẽ giúp bạn xây dựng hệ thống microservice chuẩn, giảm thiểu lỗi khi AI sinh code và tăng khả năng mở rộng. Để nắm vững toàn bộ quy trình và có các ví dụ thực tế, bạn có thể Tham khảo khóa học "Vibe Coding Masterclass với Antigravity & Stitch" tại đây.