2023 最新 FastAPI 教程:快速上手与实战 – wiki词典

2023 最新 FastAPI 教程:快速上手与实战

引言

在现代 Web 开发中,API 的构建变得越来越重要。如何快速、高效地构建高性能的 API 接口,是每一位开发者都在思考的问题。FastAPI,一个基于 Starlette 和 Pydantic 的现代、快速(高性能)的 Web 框架,凭借其卓越的性能、易用性以及强大的功能,迅速成为了 Python 社区的热门选择。本教程将带您快速上手 FastAPI,并通过实战案例深入理解其核心特性。

FastAPI 的主要优势包括:
* 极速: 媲美 NodeJS 和 Go 的高性能,得益于 Starlette (Web 部分) 和 Pydantic (数据部分)。
* 高效: 自动生成交互式 API 文档 (Swagger UI / ReDoc),大大减少了文档编写和维护的工作量。
* 健壮: 强大的数据验证和序列化功能,自动处理请求和响应。
* 易学: 语法简洁,利用 Python 类型提示,代码可读性高。
* 现代化: 完全支持异步编程 (async/await),充分利用现代 CPU 多核优势。

快速上手:构建你的第一个 FastAPI 应用

1. 安装 FastAPI 和 Uvicorn

首先,你需要安装 FastAPI 和一个 ASGI 服务器,这里我们推荐使用 Uvicorn。

bash
pip install fastapi "uvicorn[standard]"

2. 编写你的第一个 API

创建一个名为 main.py 的文件,并添加以下代码:

“`python
from fastapi import FastAPI

app = FastAPI()

@app.get(“/”)
async def read_root():
return {“message”: “Hello, FastAPI!”}

@app.get(“/items/{item_id}”)
async def read_item(item_id: int, q: str = None):
return {“item_id”: item_id, “q”: q}
“`

这段代码做了什么?
* from fastapi import FastAPI: 导入 FastAPI 类。
* app = FastAPI(): 创建 FastAPI 应用实例。
* @app.get("/"): 这是一个装饰器,将 read_root 函数注册为处理 HTTP GET 请求的根路径 (/)。
* async def read_root():: 定义一个异步函数来处理请求。FastAPI 完全支持异步,推荐使用 async def
* return {"message": "Hello, FastAPI!"}: 返回一个字典,FastAPI 会自动将其转换为 JSON 响应。
* @app.get("/items/{item_id}"): 定义另一个 GET 请求,路径中包含一个路径参数 item_id
* async def read_item(item_id: int, q: str = None):: 函数参数 item_id: int 声明了一个整数类型的路径参数。q: str = None 声明了一个可选的字符串类型查询参数。FastAPI 会自动进行类型验证。

3. 运行你的应用

在命令行中,导航到 main.py 所在的目录,然后运行:

bash
uvicorn main:app --reload

  • main: 指的是 main.py 文件。
  • app: 指的是 main.py 文件中创建的 app 对象。
  • --reload: (可选) 启用热重载,当代码更改时,服务器会自动重启。

现在,打开你的浏览器,访问 http://127.0.0.1:8000,你将看到 {"message": "Hello, FastAPI!"}
访问 http://127.0.0.1:8000/items/5?q=somequery,你将看到 {"item_id": 5, "q": "somequery"}

4. 探索自动生成的 API 文档

FastAPI 最令人惊叹的特性之一是其自动生成的 API 文档。
* Swagger UI: 访问 http://127.0.0.1:8000/docs。你将看到一个功能完善的交互式 API 文档,可以直接在页面上测试你的 API。
* ReDoc: 访问 http://127.0.0.1:8000/redoc。这提供了另一个风格的 API 文档界面。

这些文档是根据你的代码和类型提示自动生成的,极大地提高了开发效率和 API 的可维护性。

实战案例:构建一个简单的待办事项 (Todo) API

我们将创建一个更实际的 API,包含 POST (创建)、GET (读取) 和 PUT (更新) 操作。

1. 定义数据模型 (Pydantic)

FastAPI 使用 Pydantic 来进行数据验证、序列化和反序列化。创建一个新的 Python 文件或在 main.py 中添加以下内容:

“`python
from typing import Optional, List
from pydantic import BaseModel

class TodoItem(BaseModel):
id: Optional[int] = None # 用于响应,客户端创建时无需提供
title: str
description: Optional[str] = None
completed: bool = False

class TodoCreate(BaseModel):
title: str
description: Optional[str] = None

class TodoUpdate(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
completed: Optional[bool] = None

“`

  • TodoItem: 定义了待办事项的完整结构,id 是可选的,因为它通常由服务器分配。
  • TodoCreate: 定义了客户端创建待办事项时所需的数据,idcompleted 都不需要。
  • TodoUpdate: 定义了更新待办事项时可修改的字段,所有字段都是可选的。

2. 模拟数据库

为了简化,我们使用一个内存中的列表来模拟数据库。

“`python

模拟数据库

todos_db = []
next_todo_id = 1
“`

3. 实现 CRUD 操作

现在,我们将添加 API 路由来处理待办事项的创建、读取、更新和删除。

“`python
from fastapi import FastAPI, HTTPException, status, Body

… (TodoItem, TodoCreate, TodoUpdate, todos_db, next_todo_id 定义在上面)

app = FastAPI()

@app.get(“/”)
async def read_root():
return {“message”: “Welcome to the Todo API!”}

创建待办事项 (POST)

@app.post(“/todos/”, response_model=TodoItem, status_code=status.HTTP_201_CREATED)
async def create_todo(todo: TodoCreate):
global next_todo_id
new_todo = TodoItem(id=next_todo_id, **todo.dict())
todos_db.append(new_todo)
next_todo_id += 1
return new_todo

获取所有待办事项 (GET)

@app.get(“/todos/”, response_model=List[TodoItem])
async def read_todos():
return todos_db

获取单个待办事项 (GET)

@app.get(“/todos/{todo_id}”, response_model=TodoItem)
async def read_single_todo(todo_id: int):
for todo in todos_db:
if todo.id == todo_id:
return todo
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Todo not found”)

更新待办事项 (PUT)

@app.put(“/todos/{todo_id}”, response_model=TodoItem)
async def update_todo(todo_id: int, todo_update: TodoUpdate):
for idx, todo in enumerate(todos_db):
if todo.id == todo_id:
updated_data = todo_update.dict(exclude_unset=True) # 只更新提供了的字段
for key, value in updated_data.items():
setattr(todos_db[idx], key, value)
return todos_db[idx]
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Todo not found”)

删除待办事项 (DELETE)

@app.delete(“/todos/{todo_id}”, status_code=status.HTTP_204_NO_CONTENT)
async def delete_todo(todo_id: int):
global todos_db
initial_len = len(todos_db)
todos_db = [todo for todo in todos_db if todo.id != todo_id]
if len(todos_db) == initial_len:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=”Todo not found”)
return # 204 No Content 响应不需要返回内容
“`

  • @app.post("/todos/", ...): 处理创建请求。
    • response_model=TodoItem: 指定响应模型,FastAPI 会自动对响应数据进行验证和序列化。
    • status_code=status.HTTP_201_CREATED: 设置创建成功的 HTTP 状态码为 201。
    • todo: TodoCreate: FastAPI 会自动将请求体解析为 TodoCreate 实例,并进行数据验证。
  • @app.get("/todos/{todo_id}", ...): 处理获取单个待办事项请求。
    • 如果找不到,则抛出 HTTPException,FastAPI 会将其转换为适当的 HTTP 错误响应。
  • todo_update: TodoUpdate: 在 update_todo 函数中,使用 exclude_unset=True 可以确保只更新客户端实际提供的字段,而不是将未提供的字段设置为 None。
  • @app.delete("/todos/{todo_id}", ...): 处理删除请求,返回 204 状态码表示成功删除但没有内容返回。

4. 运行和测试

再次运行 uvicorn main:app --reload
访问 http://127.0.0.1:8000/docs,你将看到一个完整的 Todo API 文档,可以方便地测试所有端点:

  • POST /todos/: 创建一个待办事项。
  • GET /todos/: 获取所有待办事项。
  • GET /todos/{todo_id}: 获取指定 ID 的待办事项。
  • PUT /todos/{todo_id}: 更新指定 ID 的待办事项。
  • DELETE /todos/{todo_id}: 删除指定 ID 的待办事项。

进阶概念预览

  • 依赖注入 (Dependency Injection): FastAPI 强大的功能之一,可以轻松地管理数据库连接、用户认证等依赖项。例如,你可以定义一个依赖函数来验证用户身份,并将其注入到任何需要认证的路由中。
  • 安全性 (Security): 内置支持 OAuth2、JWT 等认证方式,可以轻松地为你的 API 添加鉴权。
  • 数据库集成: FastAPI 本身不限制数据库,可以与 SQLAlchemy、Tortoise ORM、SQLModel 等任意 ORM 或数据库库配合使用。
  • 背景任务 (Background Tasks): 允许你在发送响应后运行任务,适用于发送邮件、处理文件等耗时操作。
  • WebSockets: 支持构建实时通信应用。

总结

FastAPI 以其现代化的设计理念、卓越的性能、自动化的文档生成以及强大的类型验证,成为了 Python API 开发的利器。通过本教程,您应该已经掌握了 FastAPI 的基本用法和实战技巧,能够快速构建出高性能、易维护的 API 应用。

接下来,建议您深入阅读 FastAPI 官方文档,探索更多高级功能,如依赖注入、安全性、数据库集成等,将您的 FastAPI 应用推向新的高度!

滚动至顶部