使用 fastapi 构建 todo api:分步指南
代码可以在这里找到:
git
hub - jamesbmour/blog_tutorials:
一、简介
在上一篇文章中,我们介绍了fastapi并建立了基本的项目结构。现在,我们将更进一步,构建一个功能性的 todo api。在本教程结束时,您将拥有一个可以创建、读取、更新和删除待办事项的工作后端。
我们将涵盖的内容:
设计 todo 数据模型
实现crud操作
创建 api 端点
添加输入验证和错误处理
测试api
重构和组织代码
二.设计 todo 数据模型
为了管理待办事项,我们必须定义一个表示待办事项的数据模型。 fastapi 使用 pydantic 模型来验证和解析数据,因此我们将在这里利用它。
a. 定义 todo 模式
我们将使用 pydantic 创建两个模型:
todocreate
:用于创建或更新待办事项时的输入数据。
todo
:用于完整的待办事项,包括 id 和created_at 等字段。
b. 解释字段
id
:每个待办事项的唯一标识符。
标题
:待办事项的主要内容。
描述
:其他详细信息(可选)。
completed
:待办事项的布尔状态(无论是否完成)。
created_at
:指示待办事项创建时间的时间戳。
三.为 todos 创建 crud 操作
crud 代表创建、读取、更新和删除——管理数据的四个基本操作。在本教程中,我们将使用内存数据库(一个简单的列表)来实现这些操作。
a. 设置内存数据库
我们将使用一个列表来存储我们的待办事项。为了简单起见,我们还将添加一些示例待办事项。
b. 实现辅助函数
我们将实现一个简单的辅助函数来通过 id 查找待办事项。
四.实施 api 端点
a. 创建新的待办事项
post 端点允许用户创建新的待办事项。
b. 检索所有待办事项
get 端点从我们的内存数据库中检索所有待办事项。
c. 检索单个待办事项
get 端点允许通过 id 检索单个待办事项。
d. 更新待办事项
put 端点允许用户更新现有的待办事项。
Git
程序猿必备版本控制工具
下载
e. 删除待办事项
delete 端点允许用户通过 id 删除待办事项。
v. 添加输入验证和错误处理
a. 使用 pydantic 进行输入验证
fastapi 自动根据我们定义的 pydantic 模型验证输入数据。这确保数据在处理之前符合我们预期的模式。
b. 自定义错误处理
我们可以通过添加异常处理程序来自定义错误响应。
六.测试 api
fastapi 附带交互式 swagger ui 文档,可以轻松测试您的 api 端点。只需运行应用程序并在浏览器中导航至 /docs 即可。
测试实例
创建待办事项
:通过创建新的待办事项来测试 post 端点。
检索待办事项
:使用 get 端点获取所有待办事项或按 id 获取特定待办事项。
更新和删除
:测试 put 和 delete 端点以更新或删除待办事项。
七.重构和组织代码
随着应用程序的增长,保持代码的组织性至关重要。这里有一些提示:
a. 将模型移动到单独的文件
您可以将 pydantic 模型移动到 models.py 文件中,以保持主应用程序文件干净。
b. 为 todo 端点创建路由器
考虑为与待办事项相关的端点创建一个单独的路由器,特别是随着您的 api 的增长。
八.下一步
在下一篇文章中,我们将把一个真实的数据库(如 sqlite 或 postgresql)集成到我们的 fastapi 应用程序中。我们还将研究用户身份验证和更高级的功能。
建议的改进:
为 get 端点添加过滤和分页。
实现用户身份验证来管理个人待办事项。
九.结论
在本教程中,我们使用 fastapi 构建了一个简单的 todo api。我们首先设计一个数据模型,实现 crud 操作,并创建端点来管理待办事项。我们还涉及输入验证、错误处理和测试。有了这个基础,您可以进一步扩展 api 或将其与前端集成以创建成熟的应用程序。
如果你想支持我的写作或给我买啤酒:
https://buymeacoffee.com/bmours
from pydantic import basemodel
from typing import optional
from datetime import datetime
class todocreate(basemodel):
title: str
description: optional[str] = none
completed: bool = false
class todo(basemodel):
id: str
title: str
description: optional[str] = none
completed: bool
created_at: datetime
from uuid import uuid4
from datetime import datetime
todos = [
{
"id": str(uuid4()),
"title": "learn fastapi",
"description": "go through the official fastapi documentation and tutorials.",
"completed": false,
"created_at": datetime.now(),
},
{
"id": str(uuid4()),
"title": "build a todo api",
"description": "create a rest api for managing todo items using fastapi.",
"completed": false,
"created_at": datetime.now(),
},
{
"id": str(uuid4()),
"title": "write blog post",
"description": "draft a blog post about creating a todo api with fastapi.",
"completed": false,
"created_at": datetime.now(),
},
]
def get_todo_by_id(todo_id: str):
for todo in todos:
if todo["id"] == todo_id:
return todo
return none
@app.post("/todos/", response_model=todo)
def create_todo(todo: todocreate):
new_todo = todo(
id=str(uuid4()),
title=todo.title,
description=todo.description,
completed=todo.completed,
created_at=datetime.now()
)
todos.append(new_todo.dict())
return new_todo
@app.get("/todos/", response_model=list[todo])
def get_all_todos():
return todos
@app.get("/todos/{todo_id}", response_model=todo)
def get_todo(todo_id: str):
todo = get_todo_by_id(todo_id)
if not todo:
raise httpexception(status_code=404, detail="todo not found")
return todo
@app.put("/todos/{todo_id}", response_model=todo)
def update_todo(todo_id: str, todo_data: todocreate):
todo = get_todo_by_id(todo_id)
if not todo:
raise httpexception(status_code=404, detail="todo not found")
todo["title"] = todo_data.title
todo["description"] = todo_data.description
todo["completed"] = todo_data.completed
return todo(**todo)
@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: str):
todo = get_todo_by_id(todo_id)
if not todo:
raise httpexception(status_code=404, detail="todo not found")
todos.remove(todo)
return {"detail": "todo deleted successfully"}
@app.exception_handler(HTTPException)
def http_exception_handler(request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail},
)
