Python 工具链新体验:用 uv 和 FastAPI 十分钟搭建一个标准化 REST API

2026-07-31 0 381

每次新建Python项目,第一件事就是创建虚拟环境,然后等pip下载依赖。这个过程少则几十秒,多则几分钟,尤其网络不稳定时pip的串行下载让人恨不得去泡杯咖啡。后来有了poetry和pipenv,依赖管理好了些,但下载速度依旧没什么质变。

大概从2024年初开始,一个叫uv的工具逐渐在Python圈子里流行起来。它是用Rust写的,由发布过black和mypy的Astral团队开发,功能覆盖了虚拟环境创建、依赖安装和锁定,甚至直接接替了pip和pip-tools的角色。实际使用下来,安装速度比pip快了两个数量级,而且它的依赖解析器比pip聪明得多——解析冲突时报错信息清晰明确,不会陷入无限回溯。

正好最近要给团队内部一个微服务搭建骨架,顺便试了试用uv配合FastAPIPydantic V2来做。整个过程出乎意料地顺畅,这篇文章就把从头搭到尾的完整流程记录下来,包括环境初始化、依赖管理、模型校验、路由编写和API测试。读完之后,你可以把uv直接用到自己的下一个Python项目里。

先安装uv

uv的安装非常简单,官方提供了各平台的脚本。在macOS和Linux上,一行命令即可:

curl -LsSf https://astral.sh/uv/install.sh | sh

Windows用户可以用PowerShell安装脚本,或者通过Scoop/Chocolatey获取。安装完毕后重新打开终端,验证一下版本:

uv --version
# uv 0.2.26 (或者其他当时的最新版本)

如果已经安装了Rust工具链,也可以用cargo安装,但直接下载二进制文件更快。

创建项目并初始化虚拟环境

用uv创建一个新项目,它会同时初始化项目结构和虚拟环境,完全不需要手动调用python -m venv

# 创建一个名为 todo-api 的新项目
uv init todo-api

# 进入项目目录
cd todo-api

这个命令会在当前目录下生成一个pyproject.toml和一个默认的hello.py(可以删掉它),同时创建一个.venv虚拟环境。接下来所有操作都会自动识别这个环境,不需要显式激活——这一点体验很好,跟node_modules的逻辑类似。

添加项目依赖

现在用uv来添加FastAPI及其所需的服务器,以及Pydantic作为数据校验工具:

# 添加FastAPI和它的标准依赖
uv add fastapi

# 添加生产级服务器 uvicorn
uv add uvicorn

# 添加 Pydantic V2(FastAPI已经内置了pydantic,这里强调版本)
uv add "pydantic>=2.0"

每条命令的执行时间通常不到两秒,因为uv会并行下载并利用缓存。安装完成后,pyproject.toml里会自动添加对应的依赖项,同时生成一个uv.lock文件锁定精确版本。这个锁文件相当于package-lock.json,保证团队其他成员或部署环境安装的依赖完全一致。

如果想一次性安装多个包,也可以直接列出名称:

uv add fastapi uvicorn pydantic

编写数据模型

我们做一个简单的TODO任务管理API。先定义两个Pydantic模型:一个用于创建任务的请求体,一个用于响应。在项目根目录新建models.py

from pydantic import BaseModel, Field
from uuid import UUID, uuid4
from datetime import datetime

class TaskCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=100, description="任务标题")
    description: str = Field("", max_length=500, description="详细描述")
    is_completed: bool = Field(False)

class TaskResponse(BaseModel):
    id: UUID
    title: str
    description: str
    is_completed: bool
    created_at: datetime

Pydantic V2的数据校验更快,而且Field中可以附带丰富的元信息,这些信息会自动出现在FastAPI生成的OpenAPI文档里。注意我们没有用ORM,只是用内存字典模拟数据库,目的是聚焦API搭建流程。

创建API路由

新建main.py,编写几个核心端点:创建任务、查询任务列表、查询单个任务、更新任务状态、删除任务。全部使用异步函数,虽然这里的内存操作不是异步IO,但可以方便将来替换为异步数据库驱动。

from fastapi import FastAPI, HTTPException
from models import TaskCreate, TaskResponse
from uuid import UUID, uuid4
from datetime import datetime

app = FastAPI(title="TODO API", version="1.0.0")

# 模拟数据存储
tasks_db: dict[UUID, dict] = {}

@app.post("/tasks", response_model=TaskResponse, status_code=201)
async def create_task(task: TaskCreate):
    task_id = uuid4()
    now = datetime.utcnow()
    task_dict = task.model_dump()
    task_dict["id"] = task_id
    task_dict["created_at"] = now
    tasks_db[task_id] = task_dict
    return task_dict

@app.get("/tasks", response_model=list[TaskResponse])
async def list_tasks():
    return list(tasks_db.values())

@app.get("/tasks/{task_id}", response_model=TaskResponse)
async def get_task(task_id: UUID):
    task = tasks_db.get(task_id)
    if not task:
        raise HTTPException(status_code=404, detail="任务不存在")
    return task

@app.patch("/tasks/{task_id}", response_model=TaskResponse)
async def update_task(task_id: UUID, is_completed: bool):
    task = tasks_db.get(task_id)
    if not task:
        raise HTTPException(status_code=404, detail="任务不存在")
    task["is_completed"] = is_completed
    return task

@app.delete("/tasks/{task_id}", status_code=204)
async def delete_task(task_id: UUID):
    if task_id not in tasks_db:
        raise HTTPException(status_code=404, detail="任务不存在")
    del tasks_db[task_id]
    return None

代码本身很直白。注意我们几乎没有写任何参数校验的冗余逻辑——Pydantic模型已经保证了title不为空且长度合规,如果请求体不符合要求,FastAPI会自动返回422错误并指出具体字段问题。

启动服务并测试

用uv提供的uv run命令来启动服务,它会在项目的虚拟环境中执行命令,不需要手动激活:

uv run uvicorn main:app --reload

终端输出会显示服务地址,通常是http://127.0.0.1:8000。打开浏览器访问/docs路径,就能看到自动生成的Swagger UI交互文档。可以直接在页面里创建任务、查询列表、修改完成状态,所有接口都附带参数说明和示例——这些内容完全来自Pydantic模型的描述。

也可以用httpie或者curl测试几个端点:

# 创建任务
curl -X POST http://localhost:8000/tasks 
  -H "Content-Type: application/json" 
  -d '{"title":"学习uv","description":"了解其依赖管理和lock机制"}'

# 获取任务列表
curl http://localhost:8000/tasks

服务端的响应格式严格按照TaskResponse模型输出,字段命名保持Python风格的snake_case(FastAPI默认不会自动转换为camelCase,如果需要可以在模型中使用alias)。

uv的额外优势:锁文件和依赖树

查看当前项目的依赖树非常方便,只需:

uv tree

它会列出所有直接依赖和间接依赖的版本,并标记出是否被多个包依赖,帮助及时发现版本冲突。导出的锁文件可以用uv lock更新,用uv sync确保虚拟环境与锁文件一致。

如果想要生成类似requirements.txt的格式以便在其他工具中使用,也可以:

uv export --format requirements-txt

不过对于新项目,直接使用uv管理是最省心的。

关于异步与FastAPI的性能

上面的例子用async def定义端点,虽然内存字典操作不需要await,但FastAPI会将这些函数包装成协程运行,并且在处理请求时不会阻塞事件循环。如果将来我们把数据存储换成asyncpg(异步PostgreSQL驱动)或aioredis,只要在函数里await对应的异步操作就能无缝对接,不需要改动路由结构。

另外,Pydantic V2核心是用Rust重写的,序列化和验证速度比V1快了5到10倍,对高并发API场景有明显收益。

出现错误时的调试建议

如果在运行uv add时出现版本冲突,uv的错误信息会明确指出哪些包之间有冲突以及原因,通常比pip的报错易读。按照提示调整版本约束或者删除一些不必要的包即可。如果想让uv解析时更宽松,可以编辑pyproject.toml中的依赖限制(如从^2.0改为>=2.0)。

开发模式下,uv还支持直接引用本地路径的包(可编辑安装),这和pip的-e .类似,只需要在pyproject.toml中声明,然后用uv sync即可。

总结

整个搭建过程从敲第一行命令到跑通所有接口,耗时不到十分钟。uv替代了以往必须在Python项目初期手动处理的几个步骤:虚拟环境创建、依赖安装、锁定文件生成。FastAPI和Pydantic V2则配合着让API开发变成一件只需要描述数据结构就能自动拥有校验和文档的事情。

把这三样工具组合在一起,不只是让开发变快了,更重要的是团队协作中每个人的环境都一致,依赖变更可追溯,出问题时定位也更快。对于新启动的Python API项目来说,这个技术栈值得考虑。

Python 工具链新体验:用 uv 和 FastAPI 十分钟搭建一个标准化 REST API
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 python Python 工具链新体验:用 uv 和 FastAPI 十分钟搭建一个标准化 REST API https://www.taomawang.com/server/python/2463.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务