跳转至

完整示例:电商 API

本文档展示一个完整的电商 API 项目,包含所有 fastapi-easy 的功能。


项目结构

ecommerce-api/
├── main.py                 # 主应用文件
├── models.py               # ORM 模型
├── schemas.py              # Pydantic Schema
├── database.py             # 数据库配置
└── requirements.txt        # 依赖

1. 安装依赖

pip install fastapi uvicorn fastapi-easy sqlalchemy sqlalchemy[asyncio] aiosqlite pydantic

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. 运行应用

uvicorn main:app --reload

访问 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
  }'

删除订单

curl -X DELETE "http://localhost:8000/orders/1"

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% 代码量减少