[toc]
FastAPI笔记1 
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,专为在 Python 中构建 RESTful API 而设计。
FastAPI 特点
- 高性能: FastAPI是建立在Starlette和Pydantic之上的,利用异步(asynchronous)编程,提供出色的性能。
- 自动文档生成: 自动生成交互式API文档,支持Swagger UI和ReDoc,让API的理解和测试更加直观。
- 类型注解支持: 利用Python的类型提示,提供更严格的输入验证和更好的代码提示。
- 异步支持: 支持异步请求处理,使得处理IO密集型任务更加高效。
FastAPI 使用场景
- 构建API后端: 用于构建RESTful API,支持前后端分离的Web应用。
- 微服务架构: 可以作为微服务的后端框架,支持快速开发和部署。
- 数据处理API: 适用于处理数据,接收和返回JSON数据。
- 实时通信: 支持WebSocket,适用于实时通信场景。
什么是Starlette和Pydantic?
FastAPI是建立在Starlette和Pydantic之上的。那么Starlette和Pydantic是什么?
Starlette 是一个轻量级的异步Web库,用于构建高性能、可扩展和易维护的Web应用程序。
- Starlette是基于Python的asyncio库构建的,因此完全支持异步编程。
- Starlette的设计目标之一是保持简单和轻量级。
- Starlette提供了灵活的路由系统,可以根据URL模式将请求路由到相应的处理函数。
- Starlette内置了异常处理机制,可以捕获和处理应用程序中的异常。 ....
Pydantic 是一个用于数据验证和解析的库。它的主要目标是使数据验证变得简单且易于维护。
- Pydantic 使用Python的类型注解来定义数据模型,使得代码更具可读性和可维护性。
- Pydantic 自动验证输入数据是否符合定义的模型规范。
- Pydantic 能够将原始数据解析成Python对象。
- Pydantic 可以根据数据模型自动生成文档,包括字段名称、数据类型、默认值等信息。
Starlette和Pydantic和FastAPI的关联。

- Starlette是负责FastAPI中的web部分(异步web服务等)。
- Pydantic是负责FastAPI中的数据模型部分(类型提示等)。
FastAPI 安装 
FastAPI 依赖 Python 3.8 及更高版本。
# 使用 pip 命令来安装FastAPI
pip install fastapi另外通过FastAPI构建的web应用程序需要运行在web服务器上。因此我们还需要安装一个 ASGI 服务器,在生产环境上可以使用 Uvicorn。
Uvicorn是一个基于ASGI的高性能Web服务器,专门用于运行ASGI应用程序,即FastAPI构造的应用程序。
# 使用 pip 命令来安装uvicorn
pip install "uvicorn[standard]"第一个 FastAPI 应用 
① 创建一个 main.py 的文件,并进行编辑。
# 导入fastapi包的FastAPI类
from fastapi import FastAPI
# 创建 FastAPI 应用实例 app。用于定义和管理应用的各个组件
app = FastAPI()
# 在app应用实例上添加一个根路径 / 的路由。get请求的
@app.get("/")
def read_root():
    return {"Hello": "World"}
# 在app应用实例上添加一个路径为 /test 的异步路由。post请求的
@app.post("/test")
async def test():
    return {"test": "test"}代码解析:
- @app.get("xxx")这是一个装饰器。表示当请求路径匹配上路由的路径时,将执行这个装饰器装饰的函数。函数返回值就是请求的响应数据。
- async def test():意思是该函数是一个异步函数。没有表示是一个同步函数。
② 在main.py文件的当前目录下,命令行中运行以下命令以启动FastAPI应用程序。
# uvicorn 启动命令语法
uvicorn 文件名称:app --reload
# --reload 当文件修改后,会自动重写加载。
# main是要执行的py文件的名称
uvicorn main:app --reload
默认情况下uvicorn服务器的启动端口为8000
③ 浏览器访问各个请求路径。

④ 访问API文档
FastAPI 提供了内置的交互式 API 文档,使开发者能够轻松了解和测试 API 的各个接口。
这个文档是自动生成的,基于 OpenAPI 规范,支持 Swagger UI 和 ReDoc 两种交互式界面。
- 你可以通过访问 http://127.0.0.1:8000/docs来打开 Swagger UI 风格的文档。
- 你也可以通过访问 http://127.0.0.1:8000/redoc来打开 ReDoc 风格的文档。
如下图所示是接口文档页面 

FastAPI应用的启动端口和启动IP 
默认情况下uvicorn服务器的启动端口为8000,启动IP为127.0.0.1
下面代码可以进行更改
# --reload 当文件修改后,会自动重写加载。
# main是要执行的py文件的名称
# --host 启动ip
# --port 启动端口
uvicorn main:app --host 0.0.0.0 --port 38080 --reload路径操作装饰器 
@something语法在 Python 中被称为「装饰器」。
而在 FastAPI 中,每个路由都通过路径操作装饰器来映射到程序中的一个函数中。
简而言之,路径操作装饰器用来绑定路由和函数。
常见的路径操作装饰器如下
from fastapi import FastAPI
app = FastAPI()
## 四种HTTP请求方式的装饰器
@app.get()
@app.post()
@app.put()
@app.delete()
## 请求参数相关的装饰器
@app.options()
@app.head()
@app.patch()
@app.trace()路径操作装饰器的参数
我们可以给路径操作装饰器中传入许多参数。从而实现不同的效果。
常用的装饰器参数如下。更多的参数请查询文档。
from fastapi import FastAPI
app = FastAPI()
# 此处以post请求的路径操作装饰器举例
@app.post(
    path,
    response_model,
    status_code,
    tags,
    summary="xxx",
    description="xxx",
    response_description="xxx",
    responses,
    deprecated=False
    ....
)tags,summary,description等参数 
tags,summary,description等参数主要用于给文档中的接口添加详细信息。
例子
@app.post("/test",tags=["这是test接口的tag"],
          summary="这是test接口的summary",
          description="这是test接口的description",
          response_description="这是test接口的response_description")
def test():
    return {"Hello": "World"}文档中的效果如下图所示。 
FastAPI 路由 
APIRouter函数 
在上面的第一个 FastAPI 应用的代码中。我们是先通过FastAPI()函数创建出FastAPI应用实例,然后直接在FastAPI应用实例上添加路由。如下面代码所示。
# 导入fastapi包的FastAPI类
from fastapi import FastAPI
# 创建 FastAPI 应用实例 app。用于定义和管理应用的各个组件
app = FastAPI()
# 在app应用实例上添加一个根路径 / 的路由
@app.get("/")
def read_root():
    return {"Hello": "World"}但是这种方式不规范,这种方式是直接把FastAPI应用实例和路由进行绑定,从而导致无法区分不同种类路由。因此FastAPI提供了一个APIRouter函数,专门用于路由管理。
如下面代码所示
# 导入fastapi包的FastAPI类
from fastapi import FastAPI,APIRouter
# 创建 FastAPI 应用实例。用于定义和管理应用的各个组件
app = FastAPI()
# 创建路由实例
router = APIRouter()
# 创建根路由
@router.get("/")
def test():
    return {"Hello": "World"}
# 创建/test路由
@router.get("/test")
def test():
    return {"test": "test"}
# 通过include_router函数,把应用实例app与路由实例router绑定
app.include_router(router)- router = APIRouter()APIRouter函数用来创建路由实例。之后再路由实例上添加具体的路由。
- app.include_router(router)通过include_router函数,把应用实例app与路由实例router绑定在一起。
通过这种方式,我们可以把FastAPI的应用实例和路由实例分离开来。从而降低代码之间的耦合度。
include_router函数 
如上面代码所示,include_router函数可以将应用实例与路由实例绑定。除此之外,include_router函数还可以给不同分类的路由添加前缀,标签,注释等信息。
from fastapi import FastAPI,APIRouter
app = FastAPI()
router = APIRouter()
@router.get("/test")
def test():
    return {"Hello": "World"}
app.include_router(router,prefix="/module01",tags=["这是模块01的接口"])
多个模块的路由管理 
在正式项目中,一个FastAPI应用通常由多个模块(多个包)组件的。每个模块都拥有自己的路由。
假设一个FastAPI应用的工程目录结构如下所示。
├── fastapi-app
│   ├── __init__.py
│   ├── main.py
│   └── module01
│   │   ├── __init__.py
│   │   └── module01Routers.py
│   └── module02
│   │   ├── __init__.py
│   │   └── module02Routers.py模块01的module01Routers.py文件代码如下
from fastapi import APIRouter
router = APIRouter()
# 用户模块的测试接口
@router.get("/user/test")
async def usertest():
    return {"test": "test"}模块02的module02Routers.py文件代码如下
from fastapi import APIRouter
router = APIRouter()
# 订单模块的测试接口
@router.get("/order/test")
async def ordertest():
    return {"test": "test"}main.py文件代码如下
# 导入FastAPI
from fastapi import FastAPI
# 创建FastAPI应用实例
app = FastAPI()
# 导入各个模块
from module01 import module01Routers
from module02 import module02Routers
# 通过include_router函数,把各个模块的路由实例加入到FastAPI应用实例中
app.include_router(module01Routers.router,prefix="/module01",tags=["这是模块01的接口"])
app.include_router(module02Routers.router,prefix="/module02",tags=["这是模块02的接口"])通过上面的方式,各个模块的路由分开编写,并且通过include_router函数整合到FastAPI应用实例中。

FastAPI 请求 
FastAPI 提供了多种方式来解析请求中的数据,并根据需要生成规范的响应。
请求参数 
通常情况下请求参数是指请求路径中?后面拼接的键值对字符串。
假设请求的路径如:http://127.0.0.1:8000/test?a=1&b=2。那么请求中?后面的a=1&b=2键值对就是请求参数a和b。
from fastapi import APIRouter
router = APIRouter()
@router.get("/test")
def test(a,b):
    return {"a": a, "b": b}
# 给函数参数设置默认值
@router.get("/test2")
def test2(a: int = 0, b: int = 10):
    return {"a": a, "b": b}
# 将函数参数设置为可选参数
@router.get("/test3")
def test3(a: int = 0, b: int = None):
    return {"a": a, "b": b}- 函数形参需要与请求参数同名。这样函数形参才能接收到请求参数的数据。
- b: int = 10这种写法是把参数b的类型设置为整数类型。默认值为 10。
- b: int = None这种写法是把参数b设置为可选参数。

路径参数 
我们可以在请求路径上添加路径参数占位符。
- 路径参数占位符用来代表路径中的动态参数的。
- 当函数中的形参与路径参数同名的时候,函数形参才能接受到路径参数的数据。
from fastapi import APIRouter
router = APIRouter()
@router.get("/items/{item_id}")
def read_item(item_id: int):
    return {"item_id": item_id}- /items/{item_id}定义了一个请求路径,其中{item_id} 是路径参数,对应于函数参数 item_id。
- item_id: int函数形参item_id,数据类型为int
例子 
请求体参数-form表单数据格式 
通常情况下,GET请求的请求参数是指请求路径中?后面携带的键值对字符串。而GET请求是没有请求体的。
因此对于POST请求等。FastAPI如何接受POST请求中请求体的form表单数据?
在FastAPI中可以使用Form表单组件包来处理表单数据。
- 先安装Form表单组件包
pip install python-multipart- 使用
# 引入Form函数
from fastapi import APIRouter,Form
router = APIRouter()
# post请求
@router.post("/login")
def login(username: str = Form(),password: str = Form()):
    return {
        "username":username,
        "password":password
    }- Form()函数会拿到请求体中的表单数据。
- username: str = Form()参数username,类型为字符串。参数数据通过Form()函数来获取。
可以看到图中的Content-Type是application/x-www-form-urlencoded。这表示数据是Form表单数据。 
请求体参数-json数据格式 
通常情况下,GET请求的请求参数是指请求路径中?后面携带的键值对字符串。而GET请求是没有请求体的。
因此对于POST请求等。FastAPI如何接受POST请求中请求体的json数据?
在FastAPI中我们可以使用pydantic包来创建数据模型。通过数据模型来接收请求体中的json数据。
注意:只有自定义的数据模型类继承pydantic包中的BaseModel类。pydantic包才能帮我们将请求体的json数据进行校验并传递给模型类对象。
from pydantic import BaseModel
from fastapi import APIRouter
router = APIRouter()
# 定义Addr模型类型
class Addr(BaseModel):
    prpvince:str
    city:str
# 定义数据模型Item类及其属性。该类需要继承pydantic包中的BaseModel类
class Item(BaseModel):
    name: str
    age: int = 10               # age属性设置默认值10
    description: str = None     # 设置为可选属性
    price: float
    tax: float = None           # 设置为可选属性
    address: Addr               # 地址属性类型为Addr
# post请求
@router.post("/items/")
def create_item(item: Item):
    return item- item: Item函数参数为Item类。该参数可以接收一个请求体数据,数据的格式需要与Item类相同。

请求对象 Request 
有些情况下,我们希望可以访问Request请求对象。从而获取到请求中的一些信息。
在FastAPI中我们可以使用Request类来接收请求对象。通过这种方式我们可以获取到请求中的一些信息。例如请求头 header,请求url,cookis等
from fastapi import APIRouter,Request
router = APIRouter()
@router.post("/getRequest")
# req参数类型为Request类型。用来接收请求信息。
def getRequest(req: Request):
    return {
        "RequestURL":req.url,         
        "RequestIP":req.client.host,
        "RequestHeader":req.headers,
        "user-agent":req.headers.get("user-agent")
    }
FastAPI 响应 
响应 Json 数据 
如果路由处理函数返回一个字典类型数据,FastAPI 会把函数的返回值自动转换为 JSON 格式,并作为响应数据发送给客户端。
from fastapi import APIRouter
router = APIRouter()
@router.get("/test1/")
def test1(a, b):
    return {"a": a, "b": b}  # 返回字典数据如果路由处理函数返回一个 Pydantic 数据模型实例,FastAPI 会自动将其转换为 JSON 格式,并作为响应发送给客户端。
from fastapi import APIRouter
from pydantic import BaseModel
router = APIRouter()
# 定义数据模型类
class Item(BaseModel):
    name: str
    description: str = None
@router.post("/items/")
def get_item(item: Item):
    return item  # 返回数据模型类数据response_model 响应模型 
FastAPI提供了response_model 响应模型。让我们可以在路径操作装饰器中使用response_model参数来定义响应模型数据的格式。
from fastapi import FastAPI
app = FastAPI()
from pydantic import BaseModel
from fastapi import APIRouter
router = APIRouter()
# 定义类ItemA
class ItemA(BaseModel):
    username: str
    password: str
    age: int
# 定义类ItemB
class ItemB(BaseModel):
    username: str
    age: int
@router.post("/getItem",response_model=ItemB)
def getItem(item: ItemA):
    return item
# app应用实例中添加路由实例
app.include_router(router)- item: ItemA函数形参接收的是ItemA类对象。
- response_model=ItemB通过给路径操作装饰器添加response_model参数。来定义响应数据的格式。
运行结果如图所示 
在上面的代码中,定义了两个模型类ItemA和ItemB。路由处理函数getItem()接收并返回的都是ItemA类对象。但是最终的响应结果数据确是ItemB对象。
简而言之,若路径操作装饰器中添加了response_model参数。那么FastAPI会把函数的返回值数据转换为response_model参数声明的数据类型。
response_model_exclude_unset 参数
除了response_model参数之外,我们还可以添加 response_model_exclude_unset 参数。
response_model_exclude_unset 参数可以去除响应模型中未被赋值的字段。即响应模型中没有被赋值的字段,不会添加到响应数据中。
@router.post("/getItem",response_model=ItemB,response_model_exclude_unset=True)
def getItem(item: ItemA):
    return item函数返回的是ItemA类型的数据。但是当ItemA类型返回数据中没有被赋值的字段,不会添加到响应数据中。
response_model_include 参数
response_model_include参数可以让你更精细地控制响应数据中包含哪些字段。
@router.post("/getItem",response_model=ItemB,response_model_include={"username", "age"})
def getItem(item: ItemA):
    return item函数返回的是ItemA类型(有三个属性字段)的数据。但是response_model_include参数可以控制响应数据中只包含两个字段(username,age)的数据。
response_model_exclude 参数
response_model_include参数可以让你更精细地控制响应数据中不包含哪些字段。
@router.post("/getItem",response_model=ItemB,response_model_exclude={"password"})
def getItem(item: ItemA):
    return item函数返回的是ItemA类型(有三个属性字段)的数据。但是response_model_include参数可以控制响应数据中排除password字段数据。
重定向 
使用 RedirectResponse 实现重定向,将客户端重定向到其他路由上。
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
from fastapi import APIRouter
router = APIRouter()
@router.get("/a")
def a():
    return {"a": "a"}
@router.get("/redirect")
def redirect():
    return RedirectResponse(url="/a")  # 重定向到/a路由上在浏览器访问/redirect路由的时候会自动跳转到 /a路由。
响应状态码 
使用 HTTPException 可以抛出异常,返回自定义的状态码和详细信息。
from fastapi import HTTPException
from fastapi import APIRouter
router = APIRouter()
@router.get("/items")
def read_item():
    # 抛出HTTPException异常,参数为异常信息
    raise HTTPException(status_code=404, detail="Item not found")自定义响应数据 
使用 JSONResponse 可以自定义响应数据。
from fastapi.responses import JSONResponse
from fastapi import APIRouter
router = APIRouter()
@router.get("/items/{item_id}")
def read_item(item_id: int):
    content = {"item_id": item_id}
    headers = {"X-Custom-Header": "custom-header-value"}
    return JSONResponse(content=content, headers=headers)文件上传 
当我们需要进行文件上传的时候,需要把请求的content-type设置为multipart/form-data格式。这个格式是表单文件上传格式。
下面是文件上传的两种方式。
小文件上传 
使用fastapi包中的File函数来获取文件对象
from fastapi import APIRouter,File
router = APIRouter()
# 单个文件上传请求 (适合小文件上传)
@router.post("/uploadFile")
def uploadFile(file: bytes = File()):
    return {
        "fileLength":len(file)      # 文件字节大小
    }
# 多个文件上传请求  (适合小文件上传)
@router.post("/uploadFiles")
def uploadFiles(files: list[bytes] = File()):
    return {
        "fileCount":len(files)      # 文件个数
    }- File函数用来获取上传文件的数据。
- file: bytes = File()设置一个file参数,类型为字节数据类型。数据从File函数获取。
注意:这种方式是一次性读取文件数据内存中,因此这种方式只适合小文件上传。对于大文件上传需要用其他方法。
大文件上传 (推荐) 
使用fastapi包中的UploadFile函数来获取文件对象。
from fastapi import APIRouter,UploadFile
router = APIRouter()
# 单个文件上传请求 
@router.post("/uploadFile")
def uploadFile(file: UploadFile):
    return {
        "fileSize":file.size,         # 文件大小
        "fileName":file.filename        # 文件名称
    }
# 多个文件上传请求
@router.post("/uploadFiles")
def uploadFiles(files: list[UploadFile]):
    # 打印文件其他信息
    for i in files:
        print("fileName",i.filename)
        print("fileSize",i.size)
    return {
        "fileCount":len(files)      # 文件个数
    }- file: UploadFile设置一个file参数,是UploadFile类型。
通过UploadFile函数,我们还可以获取文件名称和大小等其他信息。

FastAPI 访问静态文件 
我们可以在FastAPI应用中开放一个静态文件目录。通过这个目录来专门访问FastAPI应用中的静态文件。
- 在main.py文件编写如下代码
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
# FastAPI应用实例对象 挂载静态目录
app.mount("/statics",StaticFiles(directory="statics"))- 先导入fastapi.staticfiles包中的StaticFiles类。
- StaticFiles(directory="statics")设置statics目录为静态文件目录。之后挂载到FastAPI应用实例对象app上。
- 注意:静态文件目录和代码文件之间的相对路径。
- 然后创建statics目录。其中创建一个txt文件
- 浏览器访问静态文件。

