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/docsTí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/redocTí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.jsonUse 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 itemKế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 itemTạ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-typescriptPython
# Tạo Python client
openapi-generator-cli generate \
-i http://localhost:8000/openapi.json \
-g python \
-o ./client-pythonGo
# Tạo Go client
openapi-generator-cli generate \
-i http://localhost:8000/openapi.json \
-g go \
-o ./client-goVí 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."""
pass2. 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):
pass4. 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(): passCá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:
- API Documentation với OpenAPI/Swagger trong Spring Boot — OpenAPI với Java và SpringDoc
- Spring Boot REST API Best Practices — Patterns cho API production-ready
Nền tảng API:
- REST API là gì? Hướng dẫn đầy đủ — Nguyên tắc REST và design patterns
- HTTP Protocol Complete Guide — Deep dive về HTTP
Tiếp tục với FastAPI:
- FastAPI Authentication & Security — Bảo mật FastAPI endpoints
- FastAPI Database Integration — Kết nối FastAPI với databases
Tham Khảo
- OpenAPI Specification: https://swagger.io/specification/
- FastAPI OpenAPI Docs: https://fastapi.tiangolo.com/advanced/extending-openapi/
- Swagger UI: https://swagger.io/tools/swagger-ui/
- ReDoc: https://github.com/Redocly/redoc
- OpenAPI Generator: https://openapi-generator.tech/
📬 Đă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.