You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI+SQLModel开发:该端点设计是否符合整洁架构?

你的FastAPI+SQLModel写法是否符合整洁架构?

首先直接给出结论:这种直接在REST端点中编写数据库逻辑的写法,并不完全符合整洁架构的核心原则,但它是FastAPI+SQLModel为快速开发设计的便捷方案——是否适用,取决于你的项目规模和长期维护需求。

为什么不符合整洁架构?

整洁架构的核心是依赖规则:内层(业务逻辑、实体)不依赖外层(Web框架、ORM、数据库),所有依赖都向内指向核心业务;同时要求关注点分离,让数据访问、业务逻辑、接口层各司其职。

而你的代码中:

  • 数据库查询(仓储层职责)直接写在FastAPI端点(Web层)中,导致Web框架层直接依赖数据访问细节,违反了依赖规则
  • 业务逻辑(如果后续需要添加,比如权限校验、数据过滤)只能嵌入端点代码,会让Web层变得臃肿,逻辑分散难以维护

FastAPI+SQLModel的设计初衷

FastAPI和SQLModel的结合确实是为了降低样板代码、加速原型开发——它们通过Pydantic实现了数据库模型和API模型的无缝转换,让开发者快速写出可运行的接口。这种写法非常适合小型项目、原型验证,但当应用规模增长后,会逐渐暴露出问题:

  1. 代码重复:多个端点会出现类似的查询逻辑,修改时要同步改多处
  2. 业务逻辑分散:所有规则都堆在端点里,时间久了端点会变成“大泥球”
  3. 测试成本高:要验证数据查询或业务逻辑,必须启动FastAPI服务,无法单独测试核心逻辑
  4. 框架锁定:如果后续更换Web框架或ORM,所有端点的数据库逻辑都要重写

如何适配整洁架构(同时保留FastAPI的优势)

结合你之前Flask+SQLAlchemy的分层经验,完全可以把这套架构迁移到FastAPI中,核心是重新划分三层职责,同时利用FastAPI的依赖注入来解耦:

1. 仓储层:封装数据访问逻辑

把所有SQLModel的Session操作集中到仓储类中,让Web层和用例层都不直接接触数据库细节:

# repository/song_repository.py
from sqlmodel import Session, select
from models.song import Song

class SongRepository:
    def __init__(self, session: Session):
        self.session = session

    def get_all_songs(self) -> list[Song]:
        result = self.session.execute(select(Song))
        return result.scalars().all()

    # 后续可以扩展其他方法:get_song_by_id、create_song等

2. 用例层:封装核心业务逻辑

用例层调用仓储层,实现业务规则(比如数据过滤、权限校验),这层是应用的核心,不依赖任何外部框架:

# use_cases/get_songs_use_case.py
from repository.song_repository import SongRepository
from models.song import Song

class GetSongsUseCase:
    def __init__(self, song_repo: SongRepository):
        self.song_repo = song_repo

    def execute(self) -> list[Song]:
        # 示例:添加业务逻辑,只返回已发布的歌曲
        all_songs = self.song_repo.get_all_songs()
        return [song for song in all_songs if song.is_published]

3. REST层:只做接口适配

FastAPI端点只负责接收请求、调用用例、返回响应,不包含任何业务或数据逻辑:

# api/songs.py
from fastapi import APIRouter, Depends
from sqlmodel import Session
from database import get_session
from repository.song_repository import SongRepository
from use_cases.get_songs_use_case import GetSongsUseCase
from models.schemas import SongRead  # 单独的Pydantic响应模型,与数据库模型解耦

router = APIRouter(prefix="/songs")

# 依赖注入:提供仓储实例
def get_song_repo(session: Session = Depends(get_session)) -> SongRepository:
    return SongRepository(session)

# 依赖注入:提供用例实例
def get_get_songs_use_case(repo: SongRepository = Depends(get_song_repo)) -> GetSongsUseCase:
    return GetSongsUseCase(repo)

@router.get("", response_model=list[SongRead])
def get_songs(use_case: GetSongsUseCase = Depends(get_get_songs_use_case)):
    return use_case.execute()

额外优化:分离数据库模型与API模型

建议把SQLModel的数据库模型(Song)和Pydantic的API模型(SongRead、SongCreate)分开,这样数据库结构的变化不会直接影响API响应格式,进一步解耦各层。

总结

  • 小型项目/原型:直接用FastAPI+SQLModel的快速写法完全没问题,开发效率优先
  • 中大型/长期维护项目:必须遵循整洁架构分层,虽然初期多写一些代码,但能让核心业务逻辑独立于框架,降低后续维护成本,也更容易扩展和测试

内容的提问来源于stack exchange,提问作者André Carvalho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 03:40:44