1. OpenAPI và Swagger là gì?

Khi xây dựng Backend, lập trình viên không chỉ cần triển khai API mà còn phải mô tả cách API hoạt động để những người khác có thể sử dụng và kiểm thử.

Ví dụ, một ứng dụng quản lý sản phẩm cung cấp các endpoint:

  • GET /products: lấy danh sách sản phẩm.
  • GET /products/{id}: lấy thông tin một sản phẩm.
  • POST /products: tạo sản phẩm mới.
  • PUT /products/{id}: cập nhật sản phẩm.
  • DELETE /products/{id}: xóa sản phẩm.

Danh sách endpoint chỉ cho biết API có những đường dẫn và phương thức HTTP nào. Để người khác có thể sử dụng API mà không cần đọc mã nguồn Backend, cần mô tả thêm các tham số, cấu trúc request body, định dạng response và những HTTP status code có thể được trả về. OpenAPI giúp chuẩn hóa các thông tin này thành tài liệu API có cấu trúc.

OpenAPI và Swagger giúp giải quyết vấn đề này.

OpenAPI là một đặc tả (specification) dùng để mô tả API theo một định dạng có cấu trúc, thường được viết bằng YAML hoặc JSON.

Swagger là tên của một hệ sinh thái công cụ hỗ trợ làm việc với đặc tả OpenAPI. Trong đó, Swagger UI là công cụ phổ biến giúp hiển thị tài liệu API dưới dạng giao diện trực quan và cho phép gửi request thử nghiệm ngay trên trình duyệt.

Có thể hiểu đơn giản:

  • OpenAPI mô tả API.
  • Swagger UI hiển thị tài liệu API và hỗ trợ tương tác với API.
  • Backend thực sự xử lý request vẫn là chương trình được triển khai bằng Go, Gin-Gonic và các thành phần liên quan.

2. OpenAPI mô tả API như thế nào?

Một tài liệu OpenAPI mô tả các endpoint, phương thức HTTP, tham số, cấu trúc dữ liệu, response và cơ chế xác thực của API.

Một số thành phần thường gặp gồm:

  • openapi: phiên bản đặc tả OpenAPI được sử dụng.
  • info: thông tin chung về API, chẳng hạn tên, phiên bản và mô tả.
  • servers: các địa chỉ cơ sở mà API có thể được truy cập.
  • paths: danh sách đường dẫn và các phương thức HTTP được hỗ trợ.
  • parameters: các tham số trên đường dẫn, query string hoặc header.
  • requestBody: cấu trúc dữ liệu client gửi lên.
  • responses: các phản hồi mà API có thể trả về.
  • components/schemas: các cấu trúc dữ liệu có thể tái sử dụng.
  • security: cách mô tả cơ chế xác thực và bảo vệ API.

Ví dụ, một phần tài liệu OpenAPI có thể được viết như sau:

openapi: 3.0.3

info:
  title: Product API
  version: 1.0.0
  description: API quản lý sản phẩm

servers:
  - url: http://localhost:8080

paths:
  /products:
    get:
      summary: Lấy danh sách sản phẩm
      responses:
        "200":
          description: Lấy danh sách thành công

Trong ví dụ này:

  • info mô tả API.
  • servers xác định địa chỉ cơ sở của API.
  • paths khai báo đường dẫn /products.
  • get mô tả thao tác sử dụng HTTP GET.
  • responses mô tả response có mã trạng thái 200.

Đây là tài liệu mô tả API, không phải mã nguồn thực hiện việc truy vấn danh sách sản phẩm. Để request hoạt động, Backend vẫn phải có endpoint tương ứng.

3. Swagger UI hoạt động như thế nào?

Swagger UI đọc tài liệu OpenAPI và hiển thị các endpoint dưới dạng giao diện tương tác.

Thay vì phải đọc tệp YAML hoặc tự xây dựng request bằng công cụ khác, người dùng có thể xem thông tin API trực tiếp trên trình duyệt.

Một quy trình sử dụng Swagger UI thường gồm:

  1. Mở trang tài liệu API.
  2. Chọn endpoint cần kiểm thử.
  3. Xem các tham số và cấu trúc request.
  4. Nhấn Try it out để nhập dữ liệu.
  5. Nhấn Execute để gửi request.
  6. Xem kết quả, bao gồm HTTP status code, response body và thông tin phản hồi.

Ví dụ, với endpoint GET /products, Swagger UI có thể gửi request đến:

GET http://localhost:8080/products

Nếu Backend xử lý thành công, Swagger UI hiển thị response mà server trả về, chẳng hạn:

[
  {
    "id": 1,
    "name": "Keyboard",
    "price": 500000
  }
]

Swagger UI không tự tạo ra dữ liệu sản phẩm. Nó chỉ gửi request đến API và hiển thị kết quả thực tế từ server.

4. OpenAPI và Swagger có vai trò gì trong dự án Backend?

4.1. Chuẩn hóa cách sử dụng API

Tài liệu OpenAPI cung cấp một bản mô tả thống nhất về cách client tương tác với Backend.

Ví dụ, khi sử dụng POST /products, người đọc có thể biết request cần trường name và price, kiểu dữ liệu của từng trường, cũng như những response có thể nhận được.

Nhờ đó, người sử dụng API không cần phải đọc toàn bộ mã nguồn Backend để hiểu cách gửi request.

4.2. Hỗ trợ phối hợp giữa Backend và Frontend

Trong một dự án, Backend và Frontend thường được phát triển bởi những người hoặc nhóm khác nhau.

Backend có thể cung cấp tài liệu OpenAPI để Frontend biết:

  • API nào đang tồn tại.
  • Cần gửi dữ liệu gì.
  • Dữ liệu phản hồi có cấu trúc ra sao.
  • Trường hợp thành công và lỗi được biểu diễn như thế nào.

Điều này giúp hai phía thống nhất cách trao đổi dữ liệu và giảm những hiểu nhầm trong quá trình tích hợp.

4.3. Hỗ trợ kiểm thử API

Swagger UI cho phép gửi request và quan sát response ngay trên giao diện tài liệu.

Lập trình viên có thể thử các endpoint, kiểm tra dữ liệu trả về và quan sát status code mà không cần viết một giao diện Frontend hoàn chỉnh trước.

Tuy nhiên, việc gửi thử request bằng Swagger UI không thay thế hoàn toàn kiểm thử tự động. Những kiểm thử quan trọng vẫn nên được xây dựng riêng để có thể chạy lặp lại khi chương trình thay đổi.

4.4. Hỗ trợ bảo trì và phát triển API

Khi API thay đổi, tài liệu cần được cập nhật tương ứng. Một tài liệu rõ ràng giúp lập trình viên mới hiểu cách sử dụng API và giúp các nhóm liên quan nắm được những thay đổi trong hệ thống.

Ngoài ra, đặc tả OpenAPI còn có thể được sử dụng với những công cụ hỗ trợ sinh mã client, tạo tài liệu hoặc hỗ trợ kiểm thử. Khả năng cụ thể phụ thuộc vào công cụ và cách đặc tả được viết.

5. Tích hợp Swagger vào dự án Go và Gin-Gonic

Trong Go, có thể sử dụng Swaggo để sinh tài liệu theo định dạng Swagger/OpenAPI từ các comment trong mã nguồn, sau đó sử dụng Swagger UI để hiển thị tài liệu.

Một thư viện thường gặp là swaggo/swag, kết hợp với swaggo/gin-swagger và swaggo/files.

Bước 1: Cài đặt các công cụ

Trong thư mục dự án Go, cài đặt các gói cần thiết:

go install github.com/swaggo/swag/cmd/swag@latest

go get github.com/swaggo/gin-swagger
go get github.com/swaggo/files

Lệnh go install cài công cụ dòng lệnh swag; các lệnh go get thêm những thư viện cần thiết vào dự án.

Bước 2: Khai báo thông tin API

Trong tệp main.go, thêm các comment mô tả API trước hàm main:

// @title Product API
// @version 1.0
// @description API quản lý sản phẩm
// @host localhost:8080
// @BasePath /
func main() {
    // ...
}

Các comment này cung cấp thông tin để công cụ Swaggo tạo tài liệu. Chúng không thay thế phần code đăng ký route hoặc xử lý request trong Gin.

Bước 3: Viết endpoint bằng Gin

Ví dụ, tạo một endpoint đơn giản:

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    router.GET("/products", func(c *gin.Context) {
        products := []gin.H{
            {
                "id":    1,
                "name":  "Keyboard",
                "price": 500000,
            },
        }

        c.JSON(http.StatusOK, products)
    })

    router.Run(":8080")
}

Đoạn code trên tạo một API GET /products, trả về danh sách sản phẩm dưới dạng JSON.

Ở ví dụ này, dữ liệu được viết trực tiếp trong code để minh họa. Trong dự án thực tế, dữ liệu có thể được lấy từ Service, Repository và database.

Bước 4: Thêm comment cho endpoint

Để Swaggo có thể sinh tài liệu cho endpoint, thêm comment ngay phía trên hàm xử lý:

// GetProducts godoc
// @Summary Lấy danh sách sản phẩm
// @Description Trả về danh sách sản phẩm
// @Tags products
// @Produce json
// @Success 200 {array} map[string]interface{}
// @Router /products [get]

Nếu sử dụng handler riêng thay vì hàm ẩn danh trong main, hãy đặt các comment này phía trên hàm handler tương ứng.

Ví dụ, endpoint có thể được tổ chức lại như sau:

// GetProducts godoc
// @Summary Lấy danh sách sản phẩm
// @Description Trả về danh sách sản phẩm
// @Tags products
// @Produce json
// @Success 200 {array} Product
// @Router /products [get]
func GetProducts(c *gin.Context) {
    // Xử lý request và trả về danh sách sản phẩm
}

Trong trường hợp này, Product cần là một kiểu dữ liệu đã được định nghĩa trong chương trình.

Bước 5: Sinh tài liệu

Sau khi viết các comment, chạy lệnh:

swag init

Công cụ sẽ phân tích mã nguồn và tạo các tệp tài liệu trong thư mục docs theo cấu hình và phiên bản công cụ đang sử dụng.

Nếu dự án có cấu trúc thư mục đặc biệt, có thể cần chỉ định đường dẫn tệp đầu vào bằng các tùy chọn của swag init.

Bước 6: Đăng ký Swagger UI với Gin

Thêm các import sau:

import (
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"

    _ "your-module/docs"
)

Thay your-module/docs bằng đường dẫn import thực tế của package docs trong dự án.

Sau đó đăng ký route hiển thị Swagger UI:

router.GET(
    "/swagger/*any",
    ginSwagger.WrapHandler(swaggerFiles.Handler),
)

Chạy ứng dụng và truy cập:

http://localhost:8080/swagger/index.html

Nếu các bước cấu hình thành công, trang Swagger UI sẽ hiển thị tài liệu API được sinh từ mã nguồn.

Lưu ý: Quy trình trên minh họa cách sử dụng Swaggo theo hệ sinh thái Swagger 2.0 phổ biến. Nếu dự án yêu cầu OpenAPI 3.x, cần lựa chọn và cấu hình công cụ tương thích với phiên bản đặc tả đó. Không nên mặc định mọi công cụ sinh tài liệu Swagger đều tạo ra OpenAPI 3.x.

6. Những lưu ý khi sử dụng OpenAPI và Swagger

Tài liệu phải khớp với API thực tế

Nếu tài liệu mô tả POST /products nhưng Backend chưa triển khai endpoint đó, Swagger UI vẫn có thể hiển thị thông tin từ tài liệu, nhưng request sẽ không hoạt động như mong đợi.

Vì vậy, tài liệu cần được cập nhật khi API thay đổi.

Mô tả rõ cả trường hợp thành công và lỗi

Không nên chỉ mô tả response 200 OK. API thực tế có thể trả về các mã như 400 Bad Request, 401 Unauthorized, 404 Not Found hoặc 500 Internal Server Error, tùy theo chức năng và cách xử lý lỗi.

Tài liệu nên phản ánh những trường hợp có thể xảy ra và cấu trúc dữ liệu tương ứng.

Không nhầm Swagger UI với công cụ kiểm thử toàn diện

Swagger UI rất hữu ích để khám phá và thử API thủ công, nhưng không tự đảm bảo tính đúng đắn của nghiệp vụ, hiệu năng, bảo mật hay khả năng chịu tải của hệ thống.

Các khía cạnh đó vẫn cần những phương pháp kiểm thử và đánh giá phù hợp.

Chú ý đến thông tin nhạy cảm

Không nên đưa mật khẩu, token thật hoặc dữ liệu cá nhân nhạy cảm vào tài liệu công khai. Đối với API nội bộ hoặc API yêu cầu xác thực, cần cấu hình quyền truy cập tài liệu phù hợp.

7. Kết luận

OpenAPI và Swagger giải quyết một nhu cầu quan trọng trong quá trình phát triển Backend: mô tả API một cách rõ ràng, thống nhất và thuận tiện để sử dụng.

OpenAPI cung cấp cấu trúc chuẩn để mô tả endpoint, request, response và cơ chế xác thực. Swagger UI giúp chuyển đặc tả đó thành giao diện trực quan để đọc tài liệu và gửi request thử nghiệm.

Khi kết hợp với Go và Gin-Gonic, các công cụ này giúp lập trình viên tài liệu hóa API, phối hợp với Frontend và kiểm thử trong quá trình phát triển. Tuy nhiên, chúng không thay thế logic xử lý của Backend hay các phương pháp kiểm thử chuyên biệt.

Hiểu được OpenAPI và Swagger là một bước hữu ích để chuyển từ việc chỉ xây dựng endpoint sang việc phát triển API có tài liệu rõ ràng, dễ tích hợp và dễ bảo trì hơn.

Nguồn tham khảo

Bài viết khác

Series 4 – React Hooks – State: Hooks, useState và useEffect

Series 4 – React Hooks – State   Bài 1 : Hooks, useState và useEffect – Quản lý dữ liệu và side effects trong React 1. React Hooks là gì? Hooks là những hàm do React cung cấp để Function Component sử dụng các khả năng như quản lý state, đồng bộ với hệ thống bên […]

Series 4 – React Fundamentals: List Rendering, Forms, Form Handling

Series 4 – React Fundamentals   Bài 3: List Rendering, Forms và Form Handling – Hiển thị danh sách và xử lý biểu mẫu trong React   1. Mở đầu Trong một ứng dụng thực tế, dữ liệu thường được hiển thị dưới dạng danh sách: danh sách sản phẩm, bài viết, người dùng hoặc công việc […]

Series 4 – React Fundamentals:  State, Events và Conditional Rendering

Series 4 – React Fundamentals   Bài 2: State, Events và Conditional Rendering – Cách React xử lý tương tác người dùng 1. Mở đầu Một giao diện website không chỉ hiển thị nội dung cố định. Khi người dùng nhấn nút, nhập dữ liệu, đăng nhập hoặc thêm sản phẩm vào giỏ hàng, giao diện cần […]

Series 4 — React Fundamentals : JSX, Components và Props – Ba nền tảng đầu tiên khi học React

Series 4 – React Fundamentals   Bài 1:JSX, Components và Props – Ba nền tảng đầu tiên khi học React 1. Mở đầu Khi xây dựng một website bằng HTML, CSS và JavaScript, chúng ta thường tạo cấu trúc giao diện bằng HTML, sau đó sử dụng JavaScript để xử lý dữ liệu và tương tác. […]

Series 3 – JavaScript Fundamentals: Async → API

Series 3 — JavaScript Fundamentals   JavaScript → DOM → Async → API   Bài 2. Asynchronous JavaScript & API – Xử lý bất đồng bộ và giao tiếp với Server 1. Vì sao cần Asynchronous JavaScript? Trong các website hiện đại, nhiều thao tác cần thời gian để hoàn thành, chẳng hạn như gọi API lấy […]

Transactions & ACID

1. Transaction là gì? Transaction (giao dịch) là một nhóm thao tác trên database được xem như một đơn vị xử lý logic. Mục tiêu là bảo đảm những thay đổi liên quan được thực hiện theo cách nhất quán: nếu giao dịch thành công thì các thay đổi cần thiết được xác nhận; nếu […]

Leave a Reply

Your email address will not be published. Required fields are marked *