1概述
FastAPI 是一个现代的高性能 Web 框架,用于使用 Python 构建 API。它旨在让开发者轻松快速高效地构建 API,同时提供 API 的自动验证、序列化和文档记录等功能,使其成为构建 Web 服务和微服务的热门选择。
在这个 FastAPI 教程中,我们将使用 FastAPI 创建一个杂货清单应用程序。在本教程结束时,你将了解如何在 Visual Studio Code 终端、编辑器和调试器中使用 FastAPI。
2设置项目
要在 VS Code 中成功完成本教程,首先需要设置 Python 开发环境。具体而言,本教程需要Python 3 和VS Code 的 Python 扩展。
在本部分中,我们将创建一个文件夹以在 VS Code 中作为工作区打开,设置 Python 虚拟环境,并安装项目的依赖项。
(1)在文件系统中,为本教程创建一个项目文件夹,例如 .groceries-plugin
(2)在 VS Code 中打开这个新文件夹(文件>打开文件夹…)。
(3)当 Workspace Trust 提示出现时,选择 Yes, I trust the authors 以允许工作区访问必要的资源和扩展。
现在,我们创建一个文件requirements.txt列出需为应用程序安装的依赖项。该requirements.txt文件是 Python 开发中的一种常见做法,用于指定项目所依赖的库及其版本。此文件有助于确保处理项目的任何人都可以重新创建类似的开发环境,使其成为保持一致性的便捷组件。
我们将安装 FastAPI 来创建应用程序,uvicorn 作为服务器,Redis 和type-redis用于处理数据存储和与 Redis 数据库交互。
(1)在 VS Code 中创建新文件(文件>新建文本文件或 Ctrl+N)。
(2)向其添加以下内容:
fastapi
redis
types-redis
uvicorn
(3)保存文件 (Ctrl+S) 并将其命名为requirements.txt 。
(4)通过打开命令面板 (Ctrl+Shift+P) 并运行 Python: Create Environment 命令来创建虚拟环境。
(5)当系统询问环境类型时,选择 Venv:
(6)然后选择计算机上可用的最新版本的 Python:
(7)从下拉列表中选择文件requirements.txt,以便自动安装依赖项,然后选择 “OK”:
以上操作将创建虚拟环境,自动安装依赖项,并为工作区选择供 Python 扩展使用的环境。你可以通过检查 VS Code 的右下角来确认它已被选中:
3开始编码
我们开始创建应用程序。
(1)使用 File > New File… 创建新的 Python 文件,然后选择 Python File。
(2)在文件夹groceries-plugin中另存为main.py (Ctrl+Shift+S)。
(3)将以下代码添加到main.py并保存该文件:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():return {"message": "Hello World"}
(4)通过启动调试器 (F5) 运行代码。
(5)从下拉菜单中,从列表中选择 FastAPI 配置选项:
这会自动创建一个调试配置,该配置调用 uvicorn 以通过调试器启动应用程序服务器,并允许你单步调试源代码以检查其行为。你应该在终端中看到类似以下内容的内容:
提示: 如果默认端口已在使用中,请停止调试器并打开命令面板 (Ctrl+Shift+P),搜索 Debug: Add Configuration,选择 Python Debugger,然后选择 FastAPI。这将创建一个自定义配置文件.vscode/launch.json,你可以在其中进行编辑。将以下内容添加到"args":[]以设置自定义端口:“–port=5000”。保存文件,然后使用 (F5) 重新启动调试器。
(6)Ctrl + 单击终端中的http://127.0.0.1:8000/ URL在默认浏览器打开该地址:
FastAPI 应用程序已启动并运行!
(7)使用调试工具栏中的 Stop 按钮或通过 Shift+F5 停止调试器。
4为杂货清单项目创建模型
现在我们已经让 FastAPI 应用程序运行起来,我们可以使用 Pydantic 定义杂货清单项目,Pydantic 是一个与 FastAPI 无缝集成的数据验证和解析库。Pydantic 允许你使用带有类型提示(type hints)的 Python 类定义数据模型,以便在 API 请求中自动验证和解析传入数据(称为“有效负载”)。
让我们为杂货清单项创建一个模型ItemPayload。我们将使用该模型来定义要添加到杂货清单中的商品的数据结构。此模型将具有三个字段:item_id 、 item_name和 quantity。
(1)使用 File > New File… 创建新的 Python 文件,然后选择 Python File。
(2)将以下行添加到models.py文件中,然后将其保存在文件夹groceries-plugin中 (Ctrl+Shift+S):
from typing import Optional
from pydantic import BaseModel
class ItemPayload(BaseModel):item_id: Optional[int]item_name: strquantity: int
Pylance 是 VS Code 中 Python 的默认语言服务器,它支持类型提示功能,这些功能对使用 Pydantic 模型和 FastAPI 非常有用。这是因为 Pylance 构建在 Pyright 之上,Pyright 是一个 Python 的静态类型检查器,可以检测代码中的类型错误,以防止错误并提高代码质量。
5创建路由
现在我们需要一个地方来存储杂货清单项目。为简单起见,我们从一个空字典开始。
(1)首先,导入示例所需的所有包。打开文件main.py并将第一行导入行替换为以下行:
from fastapi import FastAPI, HTTPException
from models import ItemPayload
(2)在app = FastAPI()下面添加以下行:
grocery_list: dict[int, ItemPayload] = {}
这将创建一个新的空字典,该字典接收int类型(作为项目 ID) 的键和ItemPayload类型的值。
现在,我们将在 FastAPI 应用程序中定义路由。在 Web 应用程序的场景中,路由类似于将特定 URL 映射到处理这些 URL 的代码的路径。这些路由用作应用程序中不同功能的入口点。当客户端(例如 Web 浏览器或其他程序)使用特定 URL 向我们的应用程序发送请求时,FastAPI 会根据 URL 将该请求路由到相应的函数(也称为路由处理程序或视图函数),该函数处理请求并生成响应。
让我们继续定义路由以添加和检索单个项目,以及返回杂货清单中的所有项目。
(3)在文件main.py末尾添加以下路由:
# Route to add a item
@app.post("/items/{item_name}/{quantity}")
def add_item(item_name: str, quantity: int):if quantity <= 0:raise HTTPException(status_code=400, detail="Quantity must be greater than 0.")# if item already exists, we'll just add the quantity.# get all item namesitems_ids = {item.item_name: item.item_id if item.item_id is not None else 0 for item in grocery_list.values()}if item_name in items_ids.keys():# get index of item_name in item_ids, which is the item_iditem_id = items_ids[item_name]grocery_list[item_id].quantity += quantity
# otherwise, create a new itemelse:# generate an ID for the item based on the highest ID in the grocery_listitem_id = max(grocery_list.keys()) + 1 if grocery_list else 0grocery_list[item_id] = ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity)return {"item": grocery_list[item_id]}
现在,我们来检查一下此路由是否按预期工作。最快的方法是使用 VS Code 的调试器以及 FastAPI 的端点/docs,它提供有关所有可用 API 路由的信息,并允许你与 API 交互以探索其参数和响应。本文档是根据 FastAPI 应用程序中定义的元数据和类型提示动态生成的。
(4)通过单击行号(或 F9)的左旁注,在if quantity <= 0语句旁边添加一个断点。调试器将在执行该行之前停止,因此你可以逐行检查代码。
(5)启动调试器 (F5),然后在浏览器中导航到http://127.0.0.1:8000/docs
这里应该有一个 Swagger 接口,其中包含应用程序中可用的两个端点:/items和 root (/)。
(6)选择/items路由旁边的向下箭头将其展开,然后选择右侧显示的 Try it out (试用) 按钮。
(7)通过将字符串传递给item_name字段并将数字传递给quantity 来添加杂货清单项。例如,你可以将 apple 作为item_name ,将 2 作为 quantity.
(8)选择 Execute。
(9)再次打开 VS Code,并注意到调试器已停止在你之前设置的断点处。
在左侧,此时定义的所有局部和全局变量都显示在 Variables 窗口中的 Run and Debug 视图下。在我们的示例中,在 locals 变量视图下item_name设置为 ‘apple’ 并设置quantity为 2,在 globals 变量视图下设置grocery_list为空字典。
现在,让我们使用 VS Code 的 Debug Console 进行一些探索。
(10)选择quantity <= 0语句,右键单击编辑器,然后选择 Evaluate in Debug Console:
这将打开 Debug Console 并运行选定的表达式。正如我们的示例中所预期的那样,表达式的计算结果为False 。
Debug Console 可以是一个强大的工具,用于快速测试表达式并更好地了解断点时代码的状态。你还可以使用它来运行任意代码,例如调用函数或打印变量。你可以在 Python 教程中了解有关 VS Code 中 Python 调试的更多信息。
现在,你可以通过在 Debug view (调试) 视图工具栏中选择 Continue (继续) 或按 F5 来继续执行代码。
最后,让我们为应用程序添加剩余的路由,以便我们可以列出所有项目或特定项目,以及将它们从我们的杂货清单中删除。你可以让调试器保持运行状态,因为当你保存下一步中所做的更改时,它将自动重新加载应用程序。
(11)将main.py 中的内容替换为以下代码:
from fastapi import FastAPI, HTTPException
from models import ItemPayloadapp = FastAPI()grocery_list: dict[int, ItemPayload] = {}# Route to add an item
@app.post("/items/{item_name}/{quantity}")
def add_item(item_name: str, quantity: int) -> dict[str, ItemPayload]:if quantity <= 0:raise HTTPException(status_code=400, detail="Quantity must be greater than 0.")# if item already exists, we'll just add the quantity.# get all item namesitems_ids: dict[str, int] = {item.item_name: item.item_id if item.item_id is not None else 0for item in grocery_list.values()}if item_name in items_ids.keys():# get index of item_name in item_ids, which is the item_iditem_id: int = items_ids[item_name]grocery_list[item_id].quantity += quantity# otherwise, create a new itemelse:# generate an ID for the item based on the highest ID in the grocery_listitem_id: int = max(grocery_list.keys()) + 1 if grocery_list else 0grocery_list[item_id] = ItemPayload(item_id=item_id, item_name=item_name, quantity=quantity)return {"item": grocery_list[item_id]}# Route to list a specific item by ID
@app.get("/items/{item_id}")
def list_item(item_id: int) -> dict[str, ItemPayload]:if item_id not in grocery_list:raise HTTPException(status_code=404, detail="Item not found.")return {"item": grocery_list[item_id]}# Route to list all items
@app.get("/items")
def list_items() -> dict[str, dict[int, ItemPayload]]:return {"items": grocery_list}# Route to delete a specific item by ID
@app.delete("/items/{item_id}")
def delete_item(item_id: int) -> dict[str, str]:if item_id not in grocery_list:raise HTTPException(status_code=404, detail="Item not found.")del grocery_list[item_id]return {"result": "Item deleted."}# Route to remove some quantity of a specific item by ID
@app.delete("/items/{item_id}/{quantity}")
def remove_quantity(item_id: int, quantity: int) -> dict[str, str]:if item_id not in grocery_list:raise HTTPException(status_code=404, detail="Item not found.")# if quantity to be removed is higher or equal to item's quantity, delete the itemif grocery_list[item_id].quantity <= quantity:del grocery_list[item_id]return {"result": "Item deleted."}else:grocery_list[item_id].quantity -= quantityreturn {"result": f"{quantity} items removed."}
(12)保存文件 (Ctrl+S)。应用程序应自动重新加载。
现在,你可以使用调试器和 Debug Console 再次打开/docs页面并测试新路由,以更好地了解代码执行情况。完成后,你可以停止调试器 (Shift+F5)。你还可以通过单击来删除我们在步骤 4 中添加的断点。
现在有了一个正在运行的 FastAPI 应用程序,其中包含用于从杂货清单中添加、列出和删除商品的路由。