Back to blog

Hiểu Về OpenAPI với FastAPI: Tài Liệu Tự Động

pythonfastapiapiopenapidocumentation
Hiểu Về OpenAPI với FastAPI: Tài Liệu Tự Động

Một trong những tính năng mạnh mẽ nhất của FastAPI là việc tự động tạo tài liệu OpenAPI. Ngay khi bạn định nghĩa API endpoints, FastAPI tạo ra tài liệu toàn diện, tương tác theo chuẩn OpenAPI (trước đây là Swagger). Hãy cùng khám phá cách nó hoạt động và cách tận dụng hiệu quả.

OpenAPI Là Gì?

OpenAPI (trước đây gọi là Swagger) là một specification để mô tả RESTful APIs. Nó cung cấp cách chuẩn để tài liệu hóa endpoints, request/response formats, phương thức authentication và nhiều hơn nữa.

Lợi Ích Chính:

  • Tiêu chuẩn hóa - Format chuẩn công nghiệp được hiểu bởi các công cụ trên toàn thế giới
  • Tự động hóa - Tạo client SDKs, server stubs và tests tự động
  • Tài liệu - Docs tương tác mà developers có thể test ngay lập tức
  • Validation - Đảm bảo API contracts được tuân thủ
  • Khả năng khám phá - Làm cho APIs dễ hiểu và sử dụng

Tạo OpenAPI Tự Động của FastAPI

FastAPI tự động tạo OpenAPI 3.0+ specifications từ Python type hints và Pydantic models của bạn. Không cần viết tài liệu thủ công!

Ví Dụ: Endpoint Cơ Bản

from fastapi import FastAPI
from pydantic import BaseModel
 
app = FastAPI()
 
class User(BaseModel):
    name: str
    email: str
    age: int
 
@app.post("/users/")
async def create_user(user: User):
    return {"message": f"Created user {user.name}"}

FastAPI Tạo Gì:

  • OpenAPI schema với định nghĩa endpoint
  • Request body schema từ model User
  • Response schema từ return type
  • Docs tương tác tại /docs (Swagger UI)
  • Docs thay thế tại /redoc (ReDoc)
  • OpenAPI JSON tại /openapi.json

Truy Cập Tài Liệu

Khi ứng dụng FastAPI đang chạy, bạn có ba endpoints tài liệu tự động:

1. Swagger UI (/docs)

# Start ứng dụng
uvicorn main:app --reload
 
# Truy cập: http://localhost:8000/docs

Tính Năng:

  • Giao diện tương tác để test endpoints
  • Thử các API calls trực tiếp trong trình duyệt
  • Xem request/response examples
  • Hỗ trợ OAuth2 authentication

2. ReDoc (/redoc)

# Truy cập: http://localhost:8000/redoc

Tính Năng:

  • Layout tài liệu sạch sẽ, chuyên nghiệp
  • Thiết kế ba panel với navigation
  • Tốt hơn cho việc đọc hơn là testing
  • Tuyệt vời để chia sẻ với stakeholders

3. OpenAPI JSON (/openapi.json)

# Truy cập: http://localhost:8000/openapi.json
# Hoặc với curl:
curl http://localhost:8000/openapi.json

Use Cases:

  • Tạo client SDKs với openapi-generator
  • Import vào Postman hoặc Insomnia
  • Validate API contracts
  • Chia sẻ API specs machine-readable

Tùy Chỉnh API Metadata

Làm tài liệu của bạn chuyên nghiệp hơn với metadata:

from fastapi import FastAPI
 
app = FastAPI(
    title="My Awesome API",
    description="API này làm những điều tuyệt vời với dữ liệu",
    version="1.0.0",
    terms_of_service="http://example.com/terms/",
    contact={
        "name": "API Support",
        "url": "http://example.com/support",
        "email": "[email protected]",
    },
    license_info={
        "name": "Apache 2.0",
        "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
    },
)

Kết Quả: Tất cả metadata này xuất hiện trong OpenAPI docs, làm cho API của bạn trông chuyên nghiệp và sẵn sàng cho production.

Tài Liệu Hóa Endpoints

Tài Liệu Cơ Bản

from fastapi import FastAPI
 
app = FastAPI()
 
@app.get(
    "/items/{item_id}",
    summary="Lấy item theo ID",
    description="Truy xuất một item cụ thể từ database bằng unique identifier.",
    response_description="Item được yêu cầu",
)
async def read_item(item_id: int):
    """
    Chi tiết bổ sung về endpoint.
    
    Bạn có thể dùng markdown ở đây:
    - Điểm 1
    - Điểm 2
    """
    return {"item_id": item_id}

Tags Để Tổ Chức

Nhóm các endpoints liên quan với tags:

@app.get("/users/", tags=["users"])
async def get_users():
    return []
 
@app.post("/users/", tags=["users"])
async def create_user():
    return {}
 
@app.get("/products/", tags=["products"])
async def get_products():
    return []

Kết Quả: Swagger UI nhóm endpoints theo tags, làm navigation dễ dàng hơn.

Tag Metadata Nâng Cao

from fastapi import FastAPI
 
tags_metadata = [
    {
        "name": "users",
        "description": "Thao tác với users. Login, đăng ký, v.v.",
    },
    {
        "name": "items",
        "description": "Quản lý items. Các thao tác CRUD.",
        "externalDocs": {
            "description": "Tài liệu external của Items",
            "url": "https://example.com/items-docs",
        },
    },
]
 
app = FastAPI(openapi_tags=tags_metadata)

Tùy Chỉnh Schema

Response Examples Tùy Chỉnh

from fastapi import FastAPI
from pydantic import BaseModel
 
app = FastAPI()
 
class Item(BaseModel):
    name: str
    price: float
    description: str | None = None
 
    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Laptop",
                    "price": 999.99,
                    "description": "Một chiếc laptop mạnh mẽ"
                }
            ]
        }
    }
 
@app.post("/items/")
async def create_item(item: Item):
    return item

Kết Quả: Swagger UI hiển thị example của bạn trong request body schema.

Field Descriptions

from pydantic import BaseModel, Field
 
class User(BaseModel):
    username: str = Field(
        ..., 
        description="Username duy nhất cho tài khoản",
        min_length=3,
        max_length=50
    )
    email: str = Field(
        ..., 
        description="Địa chỉ email của user",
        pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$"
    )
    age: int = Field(
        ..., 
        description="Tuổi của user tính bằng năm",
        ge=0,
        le=150
    )

Multiple Response Models

Tài liệu hóa các response types khác nhau:

from fastapi import FastAPI, status
from pydantic import BaseModel
 
app = FastAPI()
 
class Item(BaseModel):
    name: str
    price: float
 
class ErrorResponse(BaseModel):
    detail: str
 
@app.post(
    "/items/",
    response_model=Item,
    status_code=status.HTTP_201_CREATED,
    responses={
        201: {
            "description": "Item được tạo thành công",
            "model": Item,
        },
        400: {
            "description": "Input không hợp lệ",
            "model": ErrorResponse,
        },
        409: {
            "description": "Item đã tồn tại",
            "model": ErrorResponse,
        },
    },
)
async def create_item(item: Item):
    return item

Đánh Dấu Endpoints Deprecated

Đánh dấu endpoints là deprecated:

@app.get("/old-endpoint/", deprecated=True)
async def old_endpoint():
    """Endpoint này đã deprecated. Sử dụng /new-endpoint/ thay thế."""
    return {"message": "Đây là deprecated"}
 
@app.get("/new-endpoint/")
async def new_endpoint():
    """Sử dụng endpoint này cho implementations mới."""
    return {"message": "Đây là cách mới"}

Kết Quả: Các endpoints deprecated được đánh dấu rõ ràng trong tài liệu.

Security Schemes

OAuth2 Documentation

from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
 
app = FastAPI()
 
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
 
@app.get("/protected/")
async def protected_route(token: str = Depends(oauth2_scheme)):
    return {"token": token}

Kết Quả: Swagger UI thêm nút "Authorize" cho OAuth2 authentication.

API Key Documentation

from fastapi import FastAPI, Security
from fastapi.security import APIKeyHeader
 
app = FastAPI()
 
api_key_header = APIKeyHeader(name="X-API-Key")
 
@app.get("/secure/")
async def secure_route(api_key: str = Security(api_key_header)):
    return {"api_key": api_key}

Tùy Chỉnh OpenAPI Schema

Custom OpenAPI Schema

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
 
app = FastAPI()
 
def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
        
    openapi_schema = get_openapi(
        title="Custom API",
        version="2.5.0",
        description="Đây là custom OpenAPI schema",
        routes=app.routes,
    )
    
    # Thêm custom extensions
    openapi_schema["info"]["x-logo"] = {
        "url": "https://example.com/logo.png"
    }
    
    app.openapi_schema = openapi_schema
    return app.openapi_schema
 
app.openapi = custom_openapi

Ẩn Endpoints

Ẩn các endpoints cụ thể khỏi tài liệu:

@app.get("/internal/", include_in_schema=False)
async def internal_endpoint():
    """Sẽ không xuất hiện trong OpenAPI docs."""
    return {"message": "Chỉ sử dụng nội bộ"}

Request Body Examples

Multiple Examples

from fastapi import FastAPI, Body
from pydantic import BaseModel
 
app = FastAPI()
 
class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
 
@app.post("/items/")
async def create_item(
    item: Item = Body(
        examples={
            "normal": {
                "summary": "Ví dụ thông thường",
                "description": "Một item điển hình",
                "value": {
                    "name": "Laptop",
                    "description": "Một chiếc laptop mạnh mẽ",
                    "price": 999.99,
                },
            },
            "minimal": {
                "summary": "Ví dụ tối thiểu",
                "description": "Các fields bắt buộc tối thiểu",
                "value": {
                    "name": "Chuột",
                    "price": 19.99,
                },
            },
        }
    )
):
    return item

Tạo Client SDKs

Sử dụng OpenAPI spec để tạo client libraries:

JavaScript/TypeScript

# Cài đặt openapi-generator
npm install @openapitools/openapi-generator-cli -g
 
# Tạo TypeScript client
openapi-generator-cli generate \
  -i http://localhost:8000/openapi.json \
  -g typescript-axios \
  -o ./client-typescript

Python

# Tạo Python client
openapi-generator-cli generate \
  -i http://localhost:8000/openapi.json \
  -g python \
  -o ./client-python

Go

# Tạo Go client
openapi-generator-cli generate \
  -i http://localhost:8000/openapi.json \
  -g go \
  -o ./client-go

Ví Dụ Thực Tế: E-commerce API

Đây là ví dụ hoàn chỉnh với tài liệu OpenAPI phù hợp:

from fastapi import FastAPI, HTTPException, status, Query, Path
from pydantic import BaseModel, Field
from typing import List
from datetime import datetime
 
# API Metadata
app = FastAPI(
    title="E-commerce API",
    description="API thương mại điện tử toàn diện với quản lý sản phẩm và đơn hàng",
    version="1.0.0",
    contact={
        "name": "API Support",
        "email": "[email protected]",
    },
    license_info={
        "name": "MIT",
    },
)
 
# Models
class Product(BaseModel):
    id: int = Field(..., description="Unique product identifier")
    name: str = Field(..., description="Tên sản phẩm", min_length=1, max_length=100)
    description: str = Field(..., description="Mô tả sản phẩm")
    price: float = Field(..., description="Giá sản phẩm", gt=0)
    stock: int = Field(..., description="Số lượng tồn kho", ge=0)
    
    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "id": 1,
                    "name": "Laptop Pro 15",
                    "description": "Laptop hiệu suất cao",
                    "price": 1299.99,
                    "stock": 50
                }
            ]
        }
    }
 
@app.get(
    "/products/",
    response_model=List[Product],
    tags=["products"],
    summary="Liệt kê tất cả sản phẩm",
    description="Lấy danh sách tất cả sản phẩm có sẵn với hỗ trợ phân trang",
)
async def list_products(
    skip: int = Query(0, ge=0, description="Số items cần bỏ qua"),
    limit: int = Query(10, ge=1, le=100, description="Số items tối đa trả về"),
):
    """
    Lấy danh sách sản phẩm có phân trang.
    
    Sử dụng các tham số skip và limit để phân trang qua kết quả.
    """
    # Mock data
    return [
        Product(
            id=1,
            name="Laptop",
            description="Laptop hiệu suất cao",
            price=999.99,
            stock=10
        )
    ]

Best Practices

1. Sử Dụng Tên Mô Tả

# ❌ Không tốt
@app.get("/data/")
async def get():
    pass
 
# ✅ Tốt
@app.get("/users/")
async def get_all_users():
    """Lấy tất cả users từ database."""
    pass

2. Cung Cấp Examples

# ✅ Luôn cung cấp examples trong models
class User(BaseModel):
    name: str
    email: str
    
    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Nguyễn Văn A",
                    "email": "[email protected]"
                }
            ]
        }
    }

3. Tài Liệu Hóa Tất Cả Responses

# ✅ Tài liệu hóa cả success và error responses
@app.get(
    "/items/{item_id}",
    responses={
        200: {"description": "Thành công"},
        404: {"description": "Không tìm thấy item"},
        422: {"description": "Lỗi validation"},
    }
)
async def get_item(item_id: int):
    pass

4. Sử Dụng Tags Để Tổ Chức

# ✅ Nhóm các endpoints liên quan
@app.get("/users/", tags=["users"])
async def get_users(): pass
 
@app.post("/users/", tags=["users"])
async def create_user(): pass

Các Lỗi Phổ Biến

1. Thiếu Response Models

# ❌ Không tốt - Không có response model
@app.get("/users/")
async def get_users():
    return [{"name": "John"}]
 
# ✅ Tốt - Response model rõ ràng
@app.get("/users/", response_model=List[User])
async def get_users():
    return [User(name="John", email="[email protected]")]

2. Naming Không Nhất Quán

# ❌ Không tốt - Không nhất quán
@app.get("/getUsers/")
@app.post("/CreateUser/")
@app.delete("/delete_user/")
 
# ✅ Tốt - Tuân theo quy ước REST nhất quán
@app.get("/users/")
@app.post("/users/")
@app.delete("/users/{user_id}")

Kết Luận

Tính năng tạo OpenAPI tự động của FastAPI là một bước ngoặt cho phát triển API. Bằng cách tận dụng type hints của Python và Pydantic models, bạn có được:

  • Tài Liệu Tự Động - Không cần viết thủ công
  • Testing Tương Tác - Swagger UI và ReDoc ngay lập tức
  • Type Safety - Validation và serialization được xử lý tự động
  • Tạo Client - Generate SDKs cho bất kỳ ngôn ngữ nào
  • Chuẩn Công Nghiệp - Tương thích OpenAPI 3.0+

Chìa khóa là sử dụng các tính năng của FastAPI đúng cách: cung cấp examples, tài liệu hóa responses, tổ chức với tags, và mô tả models của bạn kỹ lưỡng. API của bạn sẽ tự tài liệu hóa, dễ sử dụng, và thú vị để làm việc.

Bắt đầu tài liệu hóa APIs theo cách FastAPI - để code tạo docs, và tập trung vào xây dựng các tính năng tuyệt vời! 🚀

Tiếp Theo

Tiếp tục hành trình phát triển API của bạn:

OpenAPI trong các Framework khác:

Nền tảng API:

Tiếp tục với FastAPI:

Tham Khảo

📬 Đăng ký nhận bản tin

Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.

Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.

💬 Comments

Đăng nhập để bình luận

Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.