当前位置: 首页 > article >正文

Python FastApi(13):APIRouter

        如果你正在开发一个应用程序或 Web API,很少会将所有的内容都放在一个文件中。FastAPI 提供了一个方便的工具,可以在保持所有灵活性的同时构建你的应用程序。假设你的文件结构如下:

.
├── app                  # 「app」是一个 Python 包
│   ├── __init__.py      # 这个文件使「app」成为一个 Python 包
│   ├── main.py          # 「main」模块,例如 import app.main
│   ├── dependencies.py  # 「dependencies」模块,例如 import app.dependencies
│   └── routers          # 「routers」是一个「Python 子包」
│   │   ├── __init__.py  # 使「routers」成为一个「Python 子包」
│   │   ├── items.py     # 「items」子模块,例如 import app.routers.items
│   │   └── users.py     # 「users」子模块,例如 import app.routers.users
│   └── internal         # 「internal」是一个「Python 子包」
│       ├── __init__.py  # 使「internal」成为一个「Python 子包」
│       └── admin.py     # 「admin」子模块,例如 import app.internal.admin

APIRouter

        假设专门用于处理用户逻辑的文件是位于 /app/routers/users.py 的子模块。你希望将与用户相关的路径操作与其他代码分开,以使其井井有条。但它仍然是同一 FastAPI 应用程序/web API 的一部分(它是同一「Python 包」的一部分)。你可以使用 APIRouter 为该模块创建路径操作。你可以导入它并通过与 FastAPI 类相同的方式创建一个「实例」:

from fastapi import APIRouterrouter = APIRouter()

        然后你可以使用它来声明路径操作。使用方式与 FastAPI 类相同:

@router.get("/users/", tags=["users"])
async def read_users():return [{"username": "Rick"}, {"username": "Morty"}]@router.get("/users/me", tags=["users"])
async def read_user_me():return {"username": "fakecurrentuser"}@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):return {"username": username}

        你可以将 APIRouter 视为一个「迷你 FastAPI」类。所有相同的选项都得到支持。我们将在主 FastAPI 应用中包含该 APIRouter。

2 依赖项

        我们将需要一些在应用程序的好几个地方所使用的依赖项。因此,我们将它们放在它们自己的 dependencies 模块(app/dependencies.py)中。现在我们将使用一个简单的依赖项来读取一个自定义的 X-Token 请求首部:

from fastapi import Header, HTTPExceptionasync def get_token_header(x_token: str = Header()):if x_token != "fake-super-secret-token":raise HTTPException(status_code=400, detail="X-Token header invalid")

APIRouter其他使用

        假设你在位于 app/routers/items.py 的模块中还有专门用于处理应用程序中「项目」的端点。你具有以下路径操作

  • /items/
  • /items/{item_id}

        我们知道此模块中的所有路径操作都有相同的:

  • 路径 prefix/items
  • tags:(仅有一个 items 标签)。
  • 额外的 responses
  • dependencies:它们都需要我们创建的 X-Token 依赖项。

        因此,我们可以将其添加到 APIRouter 中,而不是将其添加到每个路径操作中。

from fastapi import APIRouter, Depends, HTTPExceptionfrom ..dependencies import get_token_headerrouter = APIRouter(prefix="/items",tags=["items"],dependencies=[Depends(get_token_header)],responses={404: {"description": "Not found"}},
)fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}@router.get("/")
async def read_items():return fake_items_db@router.get("/{item_id}")
async def read_item(item_id: str):if item_id not in fake_items_db:raise HTTPException(status_code=404, detail="Item not found")return {"name": fake_items_db[item_id]["name"], "item_id": item_id}

        如我们所愿

  • 它们将被标记为仅包含单个字符串 "items" 的标签列表。
    • 这些「标签」对于自动化交互式文档系统(使用 OpenAPI)特别有用。
  • 所有的路径操作都将包含预定义的 responses
  • 所有的这些路径操作都将在自身之前计算/执行 dependencies 列表。
    • 如果你还在一个具体的路径操作中声明了依赖项,它们也会被执行
    • 路由器的依赖项最先执行,然后是装饰器中的 dependencies,再然后是普通的参数依赖项。

3.1 导入依赖项

        这些代码位于 app.routers.items 模块,app/routers/items.py 文件中。我们需要从 app.dependencies 模块即 app/dependencies.py 文件中获取依赖函数。因此,我们通过 .. 对依赖项使用了相对导入:

from ..dependencies import get_token_header

        一个单点 .,例如:

from .dependencies import get_token_header

        表示:

  • 从该模块(app/routers/items.py 文件)所在的同一个包(app/routers/ 目录)开始
  • 找到 dependencies 模块(一个位于 app/routers/dependencies.py 的虚构文件)
  • 然后从中导入函数 get_token_header

        但是该文件并不存在,我们的依赖项位于 app/dependencies.py 文件中。两个点 ..,例如:

from ..dependencies import get_token_header

        表示:

  • 从该模块(app/routers/items.py 文件)所在的同一个包(app/routers/ 目录)开始
  • 跳转到其父包(app/ 目录)
  • 在该父包中,找到 dependencies 模块(位于 app/dependencies.py 的文件)
  • 然后从中导入函数 get_token_header

        同样,如果我们使用了三个点 ...,例如:

from ...dependencies import get_token_header

        那将意味着:

  • 从该模块(app/routers/items.py 文件)所在的同一个包(app/routers/ 目录)开始
  • 跳转到其父包(app/ 目录
  • 然后跳转到该包的父包(该父包并不存在,app 已经是最顶层的包)
  • 在该父包中,找到 dependencies 模块(位于 app/ 更上一级目录中的 dependencies.py 文件)
  • 然后从中导入函数 get_token_header

        这将引用 app/ 的往上一级,带有其自己的 __init __.py 等文件的某个包。但是我们并没有这个包。因此,这将在我们的示例中引发错误。

3.2 添加一些自定义的 tagsresponses 和 dependencies

        我们不打算在每个路径操作中添加前缀 /items 或 tags =["items"],因为我们将它们添加到了 APIRouter 中。但是我们仍然可以添加更多将会应用于特定的路径操作的 tags,以及一些特定于该路径操作的额外 responses

from fastapi import APIRouter, Depends, HTTPExceptionfrom ..dependencies import get_token_headerrouter = APIRouter(prefix="/items",tags=["items"],dependencies=[Depends(get_token_header)],responses={404: {"description": "Not found"}},
)@router.put("/{item_id}",tags=["custom"],responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):if item_id != "plumbus":raise HTTPException(status_code=403, detail="You can only update the item: plumbus")return {"item_id": item_id, "name": "The great Plumbus"}

        最后的这个路径操作将包含标签的组合:["items","custom"]。并且在文档中也会有两个响应,一个用于 404,一个用于 403

FastAPI 主体

        现在,让我们来看看位于 app/main.py 的模块。在这里你导入并使用 FastAPI 类。这将是你的应用程序中将所有内容联结在一起的主文件。并且由于你的大部分逻辑现在都存在于其自己的特定模块中,因此主文件的内容将非常简单。

        你可以像平常一样导入并创建一个 FastAPI 类。我们甚至可以声明全局依赖项,它会和每个 APIRouter 的依赖项组合在一起。

from fastapi import Depends, FastAPIfrom .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, usersapp = FastAPI(dependencies=[Depends(get_query_token)])

        由于文件 app/routers/users.py 和 app/routers/items.py 是同一 Python 包 app 一个部分的子模块,因此我们可以使用单个点 . 通过「相对导入」来导入它们。第二个版本是「绝对导入」:

from app.routers import items, users

4.1 避免名称冲突

        我们将直接导入 items 子模块,而不是仅导入其 router 变量。这是因为我们在 users 子模块中也有另一个名为 router 的变量。如果我们一个接一个地导入,例如:

from .routers.items import router
from .routers.users import router

        来自 users 的 router 将覆盖来自 items 中的 router,我们将无法同时使用它们。因此,为了能够在同一个文件中使用它们,我们直接导入子模块:

from .routers import items, users

        现在,让我们来包含来自 users 和 items 子模块的 router

app.include_router(users.router)
app.include_router(items.router)

        使用 app.include_router(),我们可以将每个 APIRouter 添加到主 FastAPI 应用程序中。它将包含来自该路由器的所有路由作为其一部分。实际上,它将在内部为声明在 APIRouter 中的每个路径操作创建一个路径操作。所以,在幕后,它实际上会像所有的东西都是同一个应用程序一样工作。

4.2 包含一个有自定义 prefixtagsresponses 和 dependencies 的 APIRouter

        现在,假设你的组织为你提供了 app/internal/admin.py 文件。它包含一个带有一些由你的组织在多个项目之间共享的管理员路径操作的 APIRouter。对于此示例,它将非常简单。但是假设由于它是与组织中的其他项目所共享的,因此我们无法对其进行修改,以及直接在 APIRouter 中添加 prefixdependenciestags 等:

router = APIRouter()

        但是我们仍然希望在包含 APIRouter 时设置一个自定义的 prefix,以便其所有路径操作以 /admin 开头,我们希望使用本项目已经有的 dependencies 保护它,并且我们希望它包含自定义的 tags 和 responses

        我们可以通过将这些参数传递给 app.include_router() 来完成所有的声明,而不必修改原始的 APIRouter

app.include_router(admin.router,prefix="/admin",tags=["admin"],dependencies=[Depends(get_token_header)],responses={418: {"description": "I'm a teapot"}},
)

        这样,原始的 APIRouter 将保持不变,因此我们仍然可以与组织中的其他项目共享相同的 app/internal/admin.py 文件。结果是在我们的应用程序中,来自 admin 模块的每个路径操作都将具有:

  • /admin 前缀 。
  • admin 标签。
  • get_token_header 依赖项。
  • 418 响应。 🍵

        但这只会影响我们应用中的 APIRouter,而不会影响使用它的任何其他代码。因此,举例来说,其他项目能够以不同的身份认证方法使用相同的 APIRouter。我们还可以直接将路径操作添加到 FastAPI 应用中。这里我们这样做只是为了表明我们可以做到:

@app.get("/")
async def root():return {"message": "Hello Bigger Applications!"}

5 查看自动化的 API 文档

        现在,使用 app.main 模块和 app 变量运行 uvicorn。然后打开位于 http://127.0.0.1:8000/docs 的文档。你将看到使用了正确路径(和前缀)和正确标签的自动化 API 文档,包括了来自所有子模块的路径:

6 多次使用不同的 prefix 包含同一个路由器

        你也可以在同一路由器上使用不同的前缀来多次使用 .include_router()。在有些场景这可能有用,例如以不同的前缀公开同一个的 API,比方说 /api/v1 和 /api/latest。这是一个你可能并不真正需要的高级用法,但万一你有需要了就能够用上。

7 在另一个 APIRouter 中包含一个 APIRouter

        与在 FastAPI 应用程序中包含 APIRouter 的方式相同,你也可以在另一个 APIRouter 中包含 APIRouter,通过:

router.include_router(other_router)

        请确保在你将 router 包含到 FastAPI 应用程序之前进行此操作,以便 other_router 中的路径操作也能被包含进来。

相关文章:

Python FastApi(13):APIRouter

如果你正在开发一个应用程序或 Web API,很少会将所有的内容都放在一个文件中。FastAPI 提供了一个方便的工具,可以在保持所有灵活性的同时构建你的应用程序。假设你的文件结构如下: . ├── app # 「app」是一个 Python 包…...

Harmony OS“一多” 详解:基于窗口变化的断点自适应实现

一、一多开发核心概念(18N模式) 目标:一次开发多端部署 解决的问题: 1、界面级一多:适配不同屏幕尺寸 2、功能级一多:设备功能兼容性处理(CanIUser) 3、工…...

【算法竞赛】状态压缩型背包问题经典应用(蓝桥杯2019A4分糖果)

在蓝桥杯中遇到的这道题,看上去比较普通,但其实蕴含了很巧妙的“状态压缩 背包”的思想,本文将从零到一,详细解析这个问题。 目录 一、题目 二、思路分析:状态压缩 最小覆盖 1. 本质:最小集合覆盖问题…...

kali——masscan

目录 前言 使用方法 前言 Masscan 是一款快速的端口扫描工具,在 Kali Linux 系统中常被用于网络安全评估和渗透测试。 使用方法 对单个IP进行端口扫描: masscan -p11-65535 192.168.238.131 扫描指定端口: masscan -p80,22 192.168.238.131…...

常微分方程 1

slow down and take your time 定积分应用回顾常微分方程的概述一阶微分方程可分离变量齐次方程三阶线性微分方程 一阶线性微分方程不定积分的被积分函数出现了绝对值梳理微分方程的基本概念题型 1 分离变量题型 2 齐次方程5.4 题型 3 一阶线性微分方程知识点5.55.6 尾声 定积分…...

Web前端页面搭建

1.在D盘中创建www文件 cmd进入窗口命令windowsR 切换盘符d: 进入创建的文件夹 在文件夹里安装tp框架 在PS中打开tp文件 创建网站&#xff0c;根目录到public 在浏览器中打开网页 修改文件目录名称 在public目录中的。htaccess中填写下面代码 <IfModule mod_rewrite.c >…...

开源 LLM 应用开发平台 Dify 全栈部署指南(Docker Compose 方案)

开源 LLM 应用开发平台 Dify 全栈部署指南&#xff08;Docker Compose 方案&#xff09; 一、部署环境要求与前置检查 1.1 硬件最低配置 组件要求CPU双核及以上内存4GB 及以上磁盘空间20GB 可用空间 1.2 系统兼容性验证 ✅ 官方支持系统&#xff1a; Ubuntu 20.04/22.04 L…...

BN 层的作用, 为什么有这个作用?

BN 层&#xff08;Batch Normalization&#xff09;——这是深度神经网络中非常重要的一环&#xff0c;它大大改善了网络的训练速度、稳定性和收敛效果。 &#x1f9e0; 一句话理解 BN 层的作用&#xff1a; Batch Normalization&#xff08;批归一化&#xff09;通过标准化每一…...

JavaScript 中常见的鼠标事件及应用

JavaScript 中常见的鼠标事件及应用 在 JavaScript 中&#xff0c;鼠标事件是用户与网页进行交互的重要方式&#xff0c;通过监听这些事件&#xff0c;开发者可以实现各种交互效果&#xff0c;如点击、悬停、拖动等。 在 JavaScript 中&#xff0c;鼠标事件类型多样&#xff0…...

【nginx】Nginx的功能特性及常用功能

目录 1.核心功能特性1.1 高并发处理能力1.2 反向代理与负载均衡1.3 静态资源服务1.4 缓存加速1.5 SSL/TLS支持1.6 动态模块扩展1.7 流媒体服务1.8 高可用性 2.常用功能场景2.1 反向代理与负载均衡2.2 静态资源服务2.3 缓存加速2.4 HTTPS支持2.5 API网关2.6 微服务网关 3.优势总…...

make_01_Program_01_makefile .SECONDARY .dirstamp 是什么功能

在 Makefile 中&#xff0c;.SECONDARY 和 .dirstamp 与 GNU Make 处理文件和目标的方式有关。让我们分别解释这两个部分&#xff0c;以及它们结合在一起时的功能。 .SECONDARY 功能&#xff1a;.SECONDARY 是一个特殊的伪目标&#xff0c;用于告诉 make 保留所有中间目标文件…...

金仓数据库KCM认证考试介绍【2025年4月更新】

KCM&#xff08;金仓认证大师&#xff09;认证是金仓KES数据库的顶级认证&#xff0c;学员需通过前置KCA、KCP认证才能考KCM认证。 KCM培训考试一般1-2个月一次&#xff0c;KCM报名费原价为1.8万&#xff0c;当前优惠价格是1万&#xff08;趋势是&#xff1a;费用越来越高&…...

在 macOS 上安装和配置 Aria2 的详细步骤

在 macOS 上安装和配置 Aria2 的详细步骤&#xff1a; 1.安装 Aria2 方式一&#xff1a;使用 Homebrew Homebrew 是 macOS 上的包管理器&#xff0c;可以方便地安装和管理软件包。 • 打开终端。 • 输入以下命令安装 Aria2&#xff1a; brew install aria2• 检查安装是否…...

如何通过句块训练法(Chunks)提升英语口语

真正说一口流利英语的人&#xff0c;并不是会造句的人&#xff0c;而是擅长“调取句块”的人。下面我们从原理、方法、场景、资源几个维度展开&#xff0c;告诉你怎么用“句块训练法&#xff08;Chunks&#xff09;”快速提升英语口语&#xff1a; 一、什么是“句块”&#xff…...

[ctfshow web入门]burpsuite的下载与使用

下载 吾爱破解网站工具区下载burpsuite https://www.52pojie.cn/thread-1544866-1-1.html 本博客仅转载下载链接&#xff0c;下载后请按照说明进行学习使用 打开 配置 burpsuite配置 burpsuite代理设置添加127.0.0.1:8080 浏览器配置 如果是谷歌浏览器&#xff0c;打开win…...

文章记单词 | 第25篇(六级)

一&#xff0c;单词释义 mathematical&#xff1a;形容词&#xff0c;意为 “数学的&#xff1b;数学上的&#xff1b;运算能力强的&#xff1b;关于数学的”trigger&#xff1a;名词&#xff0c;意为 “&#xff08;枪的&#xff09;扳机&#xff1b;&#xff08;炸弹的&…...

vscode集成deepseek实现辅助编程(银河麒麟系统)【详细自用版】

针对开发者用户&#xff0c;可在Visual Studio Code中接入DeepSeek&#xff0c;实现辅助编程。 可参考我往期文章在银河麒麟系统环境下部署DeepSeek&#xff1a;基于银河麒麟桌面&&服务器操作系统的 DeepSeek本地化部署方法【详细自用版】 一、前期准备 &#xff08…...

【CMake】《CMake构建实战:项目开发卷》笔记-Chapter8-生成器表达式

第8章 生成器表达式 生成器表达式&#xff08;generator expression&#xff09;是由CMake生成器进行解析的表达式&#xff0c;因此&#xff0c;这些表达式只有在CMake的生成阶段才被解析为具体的值。 CMake在生成阶段&#xff0c;能够根据具体选用的构建系统生成器生成特定…...

elementui的默认样式修改

今天用element ui &#xff0c;做了个消息提示&#xff0c;发现提示的位置总是在上面&#xff0c;如图&#xff1a; 可是我想让提示的位置到下面来&#xff0c;该怎么办&#xff1f; 最后还是看了官方的api 原来有个自定义样式属性 customClass 设置下就好了 js代码 css代码 效…...

基于STM32的智能门禁系统设计与实现

一、项目背景与功能概述 在物联网技术快速发展的今天&#xff0c;传统门锁正在向智能化方向演进。本系统基于STM32F103C8T6微控制器&#xff0c;整合多种外设模块&#xff0c;实现了一个具备以下核心功能的智能门禁系统&#xff1a; 密码输入与验证&#xff08;4x3矩阵键盘&a…...

基于SpringBoot的河道水情大数据可视化分析平台设计与实现(源码+论文+部署讲解等)

需要资料&#xff0c;请文末联系 一、平台介绍 水情监测数据大屏 - 平台首页 日均水位 日均水速 二、论文内容 摘要&#xff08;中文&#xff09; 本文针对河道水情监测领域的数据管理和可视化分析需求&#xff0c;设计并实现了一套河道水情大数据可视化分析平台。该平台基…...

日志统计(双指针)

题目描述 小明维护着一个程序员论坛。现在他收集了一份"点赞"日志&#xff0c;日志共有 NN 行。其中每一行的格式是&#xff1a; ts idts id 表示在 tsts 时刻编号 idid 的帖子收到一个"赞"。 现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖…...

广告推荐算法:COSMO算法与A9算法的对比

COSMO算法与A9算法的概念解析 1. A9算法 定义与背景&#xff1a; A9算法是亚马逊早期为电商平台研发的核心搜索算法&#xff0c;主要用于优化商品搜索结果的排序和推荐&#xff0c;其核心逻辑围绕产品属性与关键词匹配展开。自2003年推出以来&#xff0c;A9通过分析商品标题…...

Java进阶之旅-day05:网络编程

引言 在当今数字化的时代&#xff0c;网络编程在软件开发中扮演着至关重要的角色。Java 作为一门广泛应用的编程语言&#xff0c;提供了强大的网络编程能力。今天&#xff0c;我们深入学习了 Java 网络编程的基础知识&#xff0c;包括基本的通信架构、网络编程三要素、IP 地址、…...

Vue 3 的响应式原理

Vue 3 的响应式原理可以比喻为“智能监控系统”&#xff1a;当数据变化时&#xff0c;它能自动追踪依赖关系并触发更新。以下是通俗解释和核心机制&#xff1a; 一、核心原理&#xff1a;Proxy 代理 Vue 3 的响应式系统基于 JavaScript 的 Proxy 对象实现&#xff08;Vue 2 使…...

Python解决“组成字符串ku的最大次数”问题

Python解决“组成字符串ku的最大次数”问题 问题描述测试样例解题思路代码 问题描述 给定一个字符串 s&#xff0c;该字符串中只包含英文大小写字母。你需要计算从字符串中最多能组成多少个字符串 “ku”。每次可以随机从字符串中选一个字符&#xff0c;并且选中的字符不能再使…...

【JS】使用滑动窗口得到无重复字符的最长子串

题目 思路 本题采用滑动窗口思想&#xff0c;定义左右指针作为滑动窗口的边界&#xff0c;使用Set数据结构处理重复字符&#xff0c;需要注意的是&#xff1a;每次遍历时采用Math.max方法实时更新最长子串的长度&#xff1b;当左指针移动时&#xff0c;set要删除对应字符。 步…...

libreoffice-help-common` 的版本(`24.8.5`)与官方源要求的版本(`24.2.7`)不一致

出现此错误的原因主要是软件包依赖冲突&#xff0c;具体分析如下&#xff1a; ### 主要原因 1. **软件源版本不匹配&#xff08;国内和官方服务器版本有差距&#xff09; 系统中可能启用了第三方软件源&#xff08;如 PPA 或 backports 源&#xff09;&#xff0c;导致 lib…...

2025-04-05 吴恩达机器学习4——逻辑回归(1):基础入门

文章目录 1 分类问题1.1 介绍1.2 线性回归与分类1.2 逻辑回归 2 逻辑回归2.1 介绍2.2 Sigmoid 函数2.3 逻辑回归模型 3 决策边界3.1 概念3.2 线性决策边界3.3 非线性决策边界 4 代价函数4.1 不使用平方误差4.2 损失函数4.3 整体代价函数 5 梯度下降5.1 参数更新5.2 逻辑回归 vs…...

P1125 [NOIP 2008 提高组] 笨小猴

#include<bits/stdc.h> using namespace std; int a[300],ma,mi105;//数组用来记录每个字符出现的次数&#xff0c;将mi初始为一个比较大的值 bool is_prime(int x){if(x0||x1)return false;for(int i2;i*i<x;i){if(x%i0)return false;}return true; }//判断是否为质…...