Prompting Tạo Structured APIs (OpenAPI/GraphQL): Tự Động Sinh Schema, Docs, Example Requests

Prompting to Generate Structured APIs: Hướng Dẫn Thực Chiến từ Người Có 12 Năm Kinh Nghiệm

Chào anh em, mình là Hải – một Senior Solutions Architect với hơn một tá năm chinh chiến trong nghề lập trình và quản lý dự án. Hôm nay mình ngồi viết bài này không phải để khoe khoang hay PR mấy cái dự án lớn, mà đơn giản là muốn chia sẻ một chủ đề đang rất “hot” và thực tế: Prompting to Generate Structured APIs (OpenAPI / GraphQL).

Nghe có vẻ phức tạp, nhưng thực ra nó đơn giản như việc bạn mô tả bằng lời muốn hệ thống làm gì, rồi nó tự sinh ra schema, docs, và cả ví dụ request luôn. Mình gọi đây là “đặc sản” của thời AI, nhưng dùng kiểu gì cho hiệu quả, chuẩn xác và đáng tin cậy thì lại là chuyện khác.


1. Mình Bắt Đầu Từ Đâu? (Hải “Mentor”)

Cách đây vài năm, mỗi lần mình muốn tạo một API mới, quy trình thường là:

  1. Viết tài liệu mô tả API bằng tay (Swagger/OpenAPI YAML hoặc JSON).
  2. Code backend.
  3. Viết lại schema GraphQL nếu dùng GraphQL.
  4. Test thủ công.
  5. Viết tài liệu hướng dẫn sử dụng.

Quá trình này tốn thời gian, dễ sai sót, và không scale. Đặc biệt khi team của bạn có 10–20 dev, mỗi người tự viết schema theo cách riêng, thì loạn cả lên.

Rồi AI đến. Ban đầu mình cũng nghi ngờ: “Liệu AI có viết schema chuẩn không? Có hiểu business logic không?”. Nhưng sau vài tháng thử nghiệm, mình nhận ra: nếu prompt đúng, AI có thể làm được rất nhiều việc.


2. Use Case Kỹ Thuật: Khi Hệ Thống Đạt 10.000 User/Giây

Mình từng làm một hệ thống thương mại điện tử cần xử lý 10.000 user đồng thời. Mỗi user đều gọi API để load danh sách sản phẩm, giỏ hàng, thanh toán. Việc viết schema bằng tay là không khả thi vì:

  • Mỗi endpoint cần được định nghĩa rõ ràng: method, path, params, body schema, response schema.
  • Cần có docs để QA và frontend có thể test nhanh.
  • Cần có ví dụ request/response để debug.

Giải pháp: Dùng AI để generate OpenAPI schema từ prompt mô tả business logic.


3. Prompting để Tạo OpenAPI Schema (Hải “Deep Dive”)

3.1. Cấu Trúc Prompt Hiệu Quả

Mình đã thử rất nhiều cách prompt, và đây là cấu trúc mình dùng hiệu quả nhất:

Bạn hãy tạo một OpenAPI 3.0 schema cho API sau:

**Business Context**: Hệ thống quản lý đơn hàng (Order Management System).
**Yêu cầu**:
- API tạo đơn hàng mới (POST /orders)
- API lấy chi tiết đơn hàng (GET /orders/{id})
- API cập nhật trạng thái đơn hàng (PATCH /orders/{id}/status)

**Input**:
- Tạo đơn: { customerId, items: [{productId, quantity, price}], shippingAddress }
- Cập nhật trạng thái: { status: "pending" | "confirmed" | "shipped" | "delivered" | "cancelled" }

**Output**:
- Response chuẩn: { success: boolean, data: {...}, message?: string }
- Error format: { success: false, error: { code, message } }

**Yêu cầu kỹ thuật**:
- Dùng JSON Schema để định nghĩa body và response.
- Có validation: required fields, type checking, enum values.
- Có ví dụ minh họa (examples) cho request và response.
- Có security scheme: API Key trong header (X-API-Key).

Hãy xuất ra file YAML OpenAPI 3.0 đầy đủ.

3.2. Kết Quả Mẫu (OpenAPI 3.0 YAML)

Dưới đây là một ví dụ schema mình đã từng generate thành công:

openapi: 3.0.3
info:
  title: Order Management API
  description: API quản lý đơn hàng cho hệ thống thương mại điện tử
  version: 1.0.0
servers:
  - url: https://api.example.com/v1
    description: Production server
paths:
  /orders:
    post:
      summary: Tạo đơn hàng mới
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
            examples:
              example-1:
                summary: Ví dụ tạo đơn hàng
                value:
                  customerId: "user_123"
                  items:
                    - productId: "prod_001"
                      quantity: 2
                      price: 299000
                    - productId: "prod_002"
                      quantity: 1
                      price: 150000
                  shippingAddress:
                    street: "123 Nguyễn Văn Cừ"
                    city: "Hà Nội"
                    country: "Vietnam"
                    zipCode: "100000"
      responses:
        '201':
          description: Tạo đơn hàng thành công
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
              examples:
                success:
                  summary: Tạo đơn thành công
                  value:
                    success: true
                    data:
                      orderId: "order_abc123"
                      status: "pending"
                      createdAt: "2025-04-05T10:00:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /orders/{id}:
    get:
      summary: Lấy chi tiết đơn hàng
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: ID của đơn hàng
          schema:
            type: string
            example: "order_abc123"
      responses:
        '200':
          description: Lấy thông tin đơn hàng thành công
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      summary: Cập nhật trạng thái đơn hàng
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: ID của đơn hàng
          schema:
            type: string
            example: "order_abc123"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrderStatusRequest'
            examples:
              shipped:
                summary: Cập nhật trạng thái thành "shipped"
                value:
                  status: "shipped"
      responses:
        '200':
          description: Cập nhật trạng thái thành công
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
  schemas:
    CreateOrderRequest:
      type: object
      required: ["customerId", "items", "shippingAddress"]
      properties:
        customerId:
          type: string
          description: "ID của khách hàng"
          example: "user_123"
        items:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/OrderItem'
        shippingAddress:
          $ref: '#/components/schemas/Address'
    OrderItem:
      type: object
      required: ["productId", "quantity", "price"]
      properties:
        productId:
          type: string
          example: "prod_001"
        quantity:
          type: integer
          minimum: 1
          example: 2
        price:
          type: number
          minimum: 0
          example: 299000
    Address:
      type: object
      required: ["street", "city", "country", "zipCode"]
      properties:
        street:
          type: string
          example: "123 Nguyễn Văn Cừ"
        city:
          type: string
          example: "Hà Nội"
        country:
          type: string
          example: "Vietnam"
        zipCode:
          type: string
          pattern: '^[0-9]{6}$'
          example: "100000"
    UpdateOrderStatusRequest:
      type: object
      required: ["status"]
      properties:
        status:
          type: string
          enum: ["pending", "confirmed", "shipped", "delivered", "cancelled"]
          example: "shipped"
    Order:
      type: object
      properties:
        orderId:
          type: string
          example: "order_abc123"
        customerId:
          type: string
          example: "user_123"
        status:
          type: string
          enum: ["pending", "confirmed", "shipped", "delivered", "cancelled"]
          example: "pending"
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        shippingAddress:
          $ref: '#/components/schemas/Address'
        createdAt:
          type: string
          format: date-time
          example: "2025-04-05T10:00:00Z"
    ApiResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          nullable: true
        message:
          type: string
          nullable: true
          example: "Request processed successfully"
  responses:
    BadRequest:
      description: Yêu cầu không hợp lệ
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalid_status:
              summary: Trạng thái không hợp lệ
              value:
                success: false
                error:
                  code: "INVALID_STATUS"
                  message: "Status must be one of: pending, confirmed, shipped, delivered, cancelled"
    Unauthorized:
      description: Không có quyền truy cập
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missing_key:
              summary: Thiếu API Key
              value:
                success: false
                error:
                  code: "UNAUTHORIZED"
                  message: "Missing or invalid API Key"
    NotFound:
      description: Không tìm thấy resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Error:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
              example: "NOT_FOUND"
            message:
              type: string
              example: "Order not found"

Lưu ý: Schema trên có thể validate bằng công cụ như Swagger Editor hoặc Redoc. Mình thường dùng Swagger UI để render docs cho team.


4. Prompting để Tạo GraphQL Schema (Hải “Architect”)

GraphQL thì khác. Nó không cần REST endpoint, mà dùng một schema duy nhất định nghĩa các Type, Query, Mutation.

4.1. Prompt Mẫu

Bạn hãy tạo một GraphQL schema (SDL) cho hệ thống quản lý đơn hàng:

**Types**:
- Order: { id, customerId, status, items, total, createdAt }
- OrderItem: { productId, productName, quantity, price }
- Address: { street, city, country, zipCode }

**Queries**:
- order(id: ID!): Order
- orders(customerId: ID!): [Order!]!

**Mutations**:
- createOrder(input: CreateOrderInput!): Order
- updateOrderStatus(id: ID!, status: OrderStatus!): Order

**Input Types**:
- CreateOrderInput: { customerId, items: [OrderItemInput!]!, shippingAddress: AddressInput! }
- OrderItemInput: { productId, quantity, price }
- AddressInput: { street, city, country, zipCode }
- OrderStatus: enum (pending, confirmed, shipped, delivered, cancelled)

Hãy xuất ra GraphQL SDL (Schema Definition Language) đầy đủ.

4.2. Kết Quả Mẫu (GraphQL SDL)

enum OrderStatus {
  pending
  confirmed
  shipped
  delivered
  cancelled
}

type Order {
  id: ID!
  customerId: ID!
  status: OrderStatus!
  items: [OrderItem!]!
  total: Float!
  shippingAddress: Address!
  createdAt: String!
}

type OrderItem {
  productId: ID!
  productName: String!
  quantity: Int!
  price: Float!
}

input OrderItemInput {
  productId: ID!
  quantity: Int!
  price: Float!
}

type Address {
  street: String!
  city: String!
  country: String!
  zipCode: String!
}

input AddressInput {
  street: String!
  city: String!
  country: String!
  zipCode: String!
}

input CreateOrderInput {
  customerId: ID!
  items: [OrderItemInput!]!
  shippingAddress: AddressInput!
}

type Query {
  order(id: ID!): Order
  orders(customerId: ID!): [Order!]!
}

type Mutation {
  createOrder(input: CreateOrderInput!): Order!
  updateOrderStatus(id: ID!, status: OrderStatus!): Order!
}

Tip: Dùng GraphQL Code Generator để tự động sinh TypeScript types từ schema này. Rất tiện cho frontend.


5. So Sánh REST (OpenAPI) vs GraphQL (Hải “Pragmatic”)

Tiêu chí OpenAPI (REST) GraphQL
Độ khó Dễ học, phổ biến Cần hiểu concept (resolver, schema)
Hiệu năng Nhiều request nếu cần nhiều resource Một request lấy hết (nhưng có thể N+1)
Documentation Swagger UI, Redoc (rất đẹp) GraphQL Playground, Apollo Studio
Type Safety JSON Schema (tốt) Strong typing (tốt hơn)
Tooling Rất phong phú (Postman, Insomnia) Apollo, Relay, Codegen
Learning Curve Dễ Trung bình

Kết luận: Nếu team bạn mới, hoặc cần integration với bên thứ 3, dùng OpenAPI. Nếu bạn cần linh hoạt truy vấn và có team frontend mạnh, hãy chọn GraphQL.


6. Lưu Ý Quan Trọng Khi Dùng AI Để Generate Schema (Hải “Security”)

⚠️ Cảnh báo: AI có thể sinh ra schema đẹp, nhưng không có nghĩa là an toàn hoặc tối ưu.

Mình từng gặp trường hợp AI sinh schema có lỗi:

  • Thiếu validation: Không có minLength, pattern, dẫn đến input injection.
  • Over-expose data: GraphQL trả về field nhạy cảm như password, internalId.
  • Không có rate limiting: Schema không định nghĩa limit số lần gọi API.

Best Practice:

  1. Luôn review schema trước khi deploy.
  2. Dùng công cụ validate: swagger-parser, graphql-config.
  3. Test với dữ liệu thực: Dùng Postman/Newman hoặc Jest để test API.
  4. Không tin 100% vào AI: Dùng AI như trợ lý, không phải thay thế dev.

7. Tích Hợp vào Quy Trình DevOps (Hải “Performance”)

Mình áp dụng quy trình sau:

  1. Prompt → Generate Schema (bằng AI).
  2. Validate schema bằng CI/CD (GitHub Actions).
  3. Generate code stub (bằng OpenAPI Generator hoặc GraphQL Codegen).
  4. Test automated với schema validation.
  5. Deploy docs (Swagger UI hoặc GraphQL Studio).

Ví dụ CI/CD Validate OpenAPI:

name: Validate OpenAPI Schema
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Validate OpenAPI
        run: |
          npm install -g @redocly/openapi-cli
          openapi lint openapi.yaml

8. Công Cụ & Tài Liệu Tham Khảo (Hải “Futurist”)

  • OpenAPI 3.0 Official Docs: https://swagger.io/specification/
  • GraphQL SDL: https://spec.graphql.org/draft/
  • Swagger Editor: https://editor.swagger.io/
  • GraphQL Code Generator: https://www.graphql-code-generator.com/
  • StackOverflow Developer Survey 2024: GraphQL usage tăng 25% so với 2022.

9. Kết Bài: 3 Key Takeaways

  1. Prompting hiệu quả = Cấu trúc rõ ràng + Ví dụ cụ thể + Yêu cầu kỹ thuật chi tiết.
  2. AI giúp tiết kiệm thời gian, nhưng không thay thế được review của dev.
  3. OpenAPI phù hợp với hệ thống lớn, cần integration. GraphQL linh hoạt nhưng cần team có kỹ năng.

10. Thảo Luận

Anh em đã từng dùng AI để generate schema bao giờ chưa? Có ai gặp trường hợp AI sinh ra schema “đẹp nhưng không dùng được” không? Cùng chia sẻ kinh nghiệm nhé!


11. Gợi Ý Công Cụ

Nếu anh em đang làm SEO hoặc content mà muốn tự động hóa quy trình, có thể tham khảo bộ công cụ bên noidungso.io.vn. Mình thấy bên đó có tích hợp AI để viết bài, check đạo văn, và xuất bản tự động – đỡ tốn cơm gạo thuê nhân sự part-time.


Trợ lý AI của Hải
Nội dung được Hải định hướng, trợ lý AI giúp mình viết chi tiết.
Chia sẻ tới bạn bè và gia đình