| Route | Method | Description | Input | Output | Middleware | Error Handling | Note |
|---|---|---|---|---|---|---|---|
/users |
GET | Lấy danh sách user | Query: page, limit, search? |
{ "data": [User], "total": int } |
auth_required, pagination |
401, 500 | Có thể filter theo name |
/users/{id} |
GET | Lấy thông tin user | Path: id |
{ "id": int, "username": str, "email": str } |
auth_required |
401, 404 | Chỉ admin hoặc chính user |
/users |
POST | Tạo user mới | Body: { "username": str, "password": str, "email": str } |
{ "id": int, "username": str } |
validate_input |
400, 409 | Email unique |
/auth/login |
POST | Đăng nhập | Body: { "username": str, "password": str } |
{ "token": str, "expires": str } |
rate_limit, validate_input |
400, 401 | JWT token trả về |
/products |
GET | Lấy danh sách sản phẩm | Query: category_id, page, limit |
{ "data": [Product] } |
optional_auth |
404, 500 | Có thể không login |
/products |
POST | Tạo sản phẩm mới | Body: { "name": str, "price": float, "category_id": int } |
{ "id": int, "name": str } |
auth_admin, validate_input |
400, 401, 409 | Chỉ admin |
/orders |
POST | Tạo đơn hàng | Body: { "user_id": int, "items": [ { "product_id": int, "qty": int } ] } |
{ "order_id": int, "total": float } |
auth_required, validate_stock |
400, 401, 404, 409 | Kiểm tra tồn kho |
/orders/{id} |
GET | Lấy chi tiết đơn hàng | Path: id |
{ "order_id": int, "items": [...], "status": str } |
auth_required |
401, 404 | Chỉ chủ đơn hàng hoặc admin |
/reports/sales |
GET | Báo cáo doanh thu | Query: start_date, end_date |
{ "total_sales": float, "orders": int } |
auth_admin |
401, 500 | Tổng hợp theo ngày |
| Middleware | Purpose | Applied to | Details |
|---|---|---|---|
auth_required |
Kiểm tra JWT token hợp lệ | /orders, /users/{id}, /reports |
Trả 401 nếu thiếu hoặc token hết hạn |
auth_admin |
Chỉ cho admin thao tác | /products (POST), /reports/sales |
Kiểm tra role trong token |
validate_input |
Xác minh schema đầu vào | Tất cả POST/PUT | Trả 400 nếu sai định dạng |
validate_stock |
Kiểm tra số lượng tồn kho | /orders |
Trả 409 nếu hết hàng |
pagination |
Chuẩn hóa dữ liệu phân trang | /users, /products |
page, limit, total count |
logging |
Ghi log request & response | Toàn bộ | Lưu file hoặc gửi đến ELK stack |
error_handler |
Chuẩn hóa response lỗi | Toàn bộ | JSON error message có code, message |
CORS |
Cho phép gọi từ frontend khác domain | Toàn bộ | Access-Control-Allow-Origin: * |
| Code | Message | Cause | Action |
|---|---|---|---|
| 400 | Invalid input | JSON không đúng schema | Kiểm tra dữ liệu gửi |
| 401 | Unauthorized | Token thiếu hoặc sai | Yêu cầu login lại |
| 403 | Forbidden | Không có quyền | Kiểm tra role user |
| 404 | Not Found | Dữ liệu không tồn tại | Trả thông báo cụ thể |
| 409 | Conflict | Trùng dữ liệu hoặc hết hàng | Thông báo rõ ràng |
| 422 | Validation error | Sai kiểu dữ liệu | Pydantic/FastAPI tự trả |
| 500 | Internal Server Error | Lỗi hệ thống | Log chi tiết server side |
backend/
├── app/
│ ├── models/ # ORM models
│ ├── schemas/ # Pydantic schemas
│ ├── crud/ # CRUD logic
│ ├── routes/ # API endpoints
│ ├── middlewares/ # auth, logging, validation
│ ├── utils/ # helper functions (jwt, hashing,...)
│ ├── config.py # settings (DB_URI, SECRET_KEY)
│ └── main.py # app entrypoint
├── migrations/ # alembic or flask-migrate
├── tests/
│ ├── unit/
│ └── integration/
├── requirements.txt
└── README.md
| Type | Content | Example |
|---|---|---|
| Unit test | Test hàm riêng lẻ | test_create_order() |
| Integration test | Gọi API thật qua TestClient | client.post("/orders", json=data) |
| Auth test | Test token hợp lệ & hết hạn | 401, 403 |
| Validation test | Test input thiếu field | 400 |
| Business rule test | Sản phẩm hết hàng | 409 |
| Pagination test | page/limit hoạt động đúng | 200 + tổng count |
- FastAPI tự sinh
/docsvà/redoc - Ghi rõ input/output, error code
- Thêm tag cho mỗi nhóm route (
users,orders,products)