完整示例:电商 API¶
本文档展示一个完整的电商 API 项目,包含所有 fastapi-easy 的功能。
项目结构¶
ecommerce-api/
├── main.py # 主应用文件
├── models.py # ORM 模型
├── schemas.py # Pydantic Schema
├── database.py # 数据库配置
└── requirements.txt # 依赖
1. 安装依赖¶
requirements.txt:
fastapi>=0.100
uvicorn[standard]>=0.23
fastapi-easy>=1.0
sqlalchemy>=2.0
aiosqlite>=0.19
pydantic>=2.0
2. 数据库配置¶
database.py:
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "sqlite+aiosqlite:///./ecommerce.db"
engine = create_async_engine(
DATABASE_URL,
echo=False,
future=True
)
AsyncSessionLocal = sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False
)
async def get_db():
async with AsyncSessionLocal() as session:
yield session
3. ORM 模型¶
models.py:
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey
from sqlalchemy.orm import declarative_base
from datetime import datetime
Base = declarative_base()
class CategoryDB(Base):
__tablename__ = "categories"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, unique=True, index=True)
description = Column(String)
class ProductDB(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
description = Column(String)
price = Column(Float, index=True)
stock = Column(Integer, index=True)
category_id = Column(Integer, ForeignKey("categories.id"))
created_at = Column(DateTime, default=datetime.utcnow, index=True)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class OrderDB(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True, index=True)
order_number = Column(String, unique=True, index=True)
total_price = Column(Float)
status = Column(String, default="pending", index=True)
created_at = Column(DateTime, default=datetime.utcnow, index=True)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
4. Pydantic Schema¶
schemas.py:
from pydantic import BaseModel
from datetime import datetime
from typing import Optional
# Category Schema
class Category(BaseModel):
id: int
name: str
description: Optional[str] = None
class Config:
from_attributes = True
# Product Schema
class Product(BaseModel):
id: int
name: str
description: Optional[str] = None
price: float
stock: int
category_id: int
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
# Order Schema
class Order(BaseModel):
id: int
order_number: str
total_price: float
status: str
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
5. 主应用¶
main.py:
from fastapi import FastAPI
from fastapi_easy import CRUDRouter
from fastapi_easy.backends import SQLAlchemyAsyncBackend
from fastapi_easy.features import PaginationConfig, SoftDeleteConfig
from database import engine, get_db
from models import Base, CategoryDB, ProductDB, OrderDB
from schemas import Category, Product, Order
# 创建表
@app.on_event("startup")
async def startup():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# 创建应用
app = FastAPI(
title="电商 API",
description="完整的电商 API 示例",
version="1.0.0"
)
# ============ Category 路由 ============
category_router = CRUDRouter(
schema=Category,
backend=SQLAlchemyAsyncBackend(CategoryDB, get_db),
prefix="/categories",
tags=["categories"],
enable_filters=True,
filter_fields=["name"],
enable_sorters=True,
sort_fields=["name", "id"],
enable_pagination=True,
pagination_config=PaginationConfig(default_limit=10, max_limit=100),
)
# ============ Product 路由 ============
product_router = CRUDRouter(
schema=Product,
backend=SQLAlchemyAsyncBackend(ProductDB, get_db),
prefix="/products",
tags=["products"],
enable_filters=True,
filter_fields=["name", "price", "stock", "category_id"],
enable_sorters=True,
sort_fields=["name", "price", "created_at", "stock"],
default_sort="-created_at",
enable_pagination=True,
pagination_config=PaginationConfig(default_limit=20, max_limit=100),
)
# ============ Order 路由 ============
order_router = CRUDRouter(
schema=Order,
backend=SQLAlchemyAsyncBackend(OrderDB, get_db),
prefix="/orders",
tags=["orders"],
enable_filters=True,
filter_fields=["order_number", "status"],
enable_sorters=True,
sort_fields=["created_at", "total_price", "status"],
default_sort="-created_at",
enable_pagination=True,
pagination_config=PaginationConfig(default_limit=10, max_limit=100),
enable_soft_delete=True,
soft_delete_config=SoftDeleteConfig(deleted_at_field="deleted_at"),
)
# 注册路由
app.include_router(category_router)
app.include_router(product_router)
app.include_router(order_router)
# 根路由
@app.get("/")
async def root():
return {
"message": "欢迎来到电商 API",
"docs": "/docs",
"endpoints": {
"categories": "/categories",
"products": "/products",
"orders": "/orders"
}
}
6. 运行应用¶
访问 http://localhost:8000/docs 查看 API 文档
7. API 使用示例¶
创建分类¶
curl -X POST "http://localhost:8000/categories" \
-H "Content-Type: application/json" \
-d '{
"name": "水果",
"description": "新鲜水果"
}'
创建商品¶
curl -X POST "http://localhost:8000/products" \
-H "Content-Type: application/json" \
-d '{
"name": "苹果",
"description": "新鲜苹果",
"price": 15.5,
"stock": 100,
"category_id": 1
}'
查询商品(带过滤、排序、分页)¶
# 查询价格大于 10 的商品,按价格降序,每页 10 条
curl "http://localhost:8000/products?price__gt=10&sort=-price&skip=0&limit=10"
# 查询分类为 1 且库存大于 0 的商品
curl "http://localhost:8000/products?category_id=1&stock__gt=0"
# 查询名称包含 "苹果" 的商品,按创建时间降序
curl "http://localhost:8000/products?name__like=%苹果%&sort=-created_at"
创建订单¶
curl -X POST "http://localhost:8000/orders" \
-H "Content-Type: application/json" \
-d '{
"order_number": "ORD-001",
"total_price": 150.0,
"status": "pending"
}'
查询订单¶
# 查询所有待处理订单,按创建时间降序
curl "http://localhost:8000/orders?status=pending&sort=-created_at"
# 查询特定订单号
curl "http://localhost:8000/orders?order_number=ORD-001"
更新商品¶
curl -X PUT "http://localhost:8000/products/1" \
-H "Content-Type: application/json" \
-d '{
"name": "新鲜苹果",
"price": 18.0,
"stock": 80
}'
删除订单¶
8. 代码量对比¶
手写方式¶
models.py ~100 行
schemas.py ~80 行
routes/categories.py ~150 行
routes/products.py ~200 行
routes/orders.py ~200 行
database.py ~50 行
main.py ~100 行
─────────────────────────────
总计 ~880 行
使用 fastapi-easy¶
models.py ~100 行
schemas.py ~80 行
database.py ~50 行
main.py ~120 行
─────────────────────────────
总计 ~350 行
节约: 60% 代码量减少 ✨
9. 自动生成的 API¶
Categories¶
GET /categories- 获取所有分类GET /categories/{id}- 获取单个分类POST /categories- 创建分类PUT /categories/{id}- 更新分类DELETE /categories/{id}- 删除分类
Products¶
GET /products- 获取所有商品(支持过滤、排序、分页)GET /products/{id}- 获取单个商品POST /products- 创建商品PUT /products/{id}- 更新商品DELETE /products/{id}- 删除商品
Orders¶
GET /orders- 获取所有订单(支持过滤、排序、分页)GET /orders/{id}- 获取单个订单POST /orders- 创建订单PUT /orders/{id}- 更新订单DELETE /orders/{id}- 删除订单(软删除)
10. 功能特性¶
✅ 完整的 CRUD 操作 ✅ 搜索和过滤 ✅ 排序 ✅ 分页 ✅ 软删除 ✅ 自动 OpenAPI 文档 ✅ 异步支持 ✅ Pydantic v2 兼容
11. 下一步¶
- 添加权限控制
- 添加审计日志
- 添加业务逻辑钩子
- 添加关系处理
- 添加批量操作
总结¶
这个完整示例展示了如何使用 fastapi-easy 快速构建一个功能完整的电商 API,只需要约 350 行代码,而手写方式需要约 880 行代码。
效率提升: 60% 代码量减少 ✨