两个核心组件

  • Web 框架部分: 由 Starlette 提供。它处理路由、请求和响应等核心 Web 功能。
  • 数据模型部分: 由 Pydantic 提供。它负责数据验证和解析,通过类型注解确保数据的正确性和一致性。

Starlette

Starlette 是一个用于构建异步 Web 应用程序的轻量级 ASGI 框架。它的主要特点包括:

  • 高性能: 设计用于处理高并发请求。
  • 异步支持: 完全支持 Python 的异步编程,适合构建现代异步 Web 应用。
  • 丰富的功能: 包括路由、中间件、会话、CORS、WebSocket 等。
  • 易于扩展: 可以通过插件和中间件轻松扩展功能。

Starlette 通常用于构建快速、高效的 API 服务,是 FastAPI 的基础框架。

下面是 FastAPI 的官网介绍

FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 并基于标准的 Python 类型提示。

关键特性:

  • 快速:可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic)。最快的 Python web 框架之一

  • 高效编码:提高功能开发速度约 200% 至 300%。*

  • 更少 bug:减少约 40% 的人为(开发者)导致错误。*

  • 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间。

  • 简单:设计的易于使用和学习,阅读文档的时间更短。

  • 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。

  • 健壮:生产可用级别的代码。还有自动生成的交互式文档。

  • 标准化:基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema

Pydantic 应用举例

当然,可以举个例子来说明。

假设你有一个 Pydantic 模型 User,定义如下:

1
2
3
4
5
6
7
8
9
from pydantic import BaseModel
from typing import Optional
from datetime import datetime

class User(BaseModel):
    id: int
    name: str = "Anonymous"
    signup_ts: Optional[datetime] = None
    friends: list[int] = []

现在,你有一组外部数据,比如从一个 API 请求中接收到的数据:

1
2
3
4
5
6
external_data = {
    "id": 123,
    "name": "Alice",
    "signup_ts": "2023-11-18T12:34:56",
    "friends": [456, 789]
}

使用 user = User(**external_data),你可以这样创建一个 User 实例:

1
user = User(**external_data)

这个过程会:

  1. 解包: external_data

    • id=123
    • name="Alice"
    • signup_ts="2023-11-18T12:34:56"
    • friends=[456, 789]
  2. 验证和解析

    • Pydantic 会检查这些字段是否符合 User 模型的定义。如果比如传入 string 类型,规定是 int 类型会进行数据转换,如果传入不是数字类无法转换则报错。
    • signup_ts 会被解析为 datetime 对象。
  3. 创建实例

    • 如果所有字段都有效,则创建一个 User 实例。
    • 如果有任何字段不符合要求,会抛出验证错误。

最终,user 是一个 User 模型的实例,包含解析和验证后的数据。

quick start

(1) 导入 FastAPI. (2) 创建一个 app 实例. (3) 编写一个路径操作装饰器 (如@app. get ("/")). (4) 编写一个路径操作函数 (如上面的 def root ():...)(5) 定义返回值 (6) 运行开发服务器 (如 uvicorn main: app--reload)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from fastapi import FastAPI

import uvicorn

  

app = FastAPI()

  
  
  

@app.get("/")

def root():

    return {"message": "Hello World"}

  
  
  

if __name__ == "__main__":

    uvicorn.run("server:app", port=8000,reload=True)

路径操作

路径操作修饰器

在 FastAPI 中,路径操作修饰器用于定义处理特定 HTTP 请求的方法。常用的修饰器包括 @app.get()@app.post()@app.put()@app.delete() 等。它们用于指定不同的 HTTP 方法和路径。

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello World"}

@app.post("/items/")
async def create_item(item: dict):
    return {"item": item}

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: dict):
    return {"item_id": item_id, "item": item}

@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
    return {"item_id": item_id, "status": "deleted"}

说明

  • @app.get("/"):处理 GET 请求,路径为 /
  • @app.post("/items/"):处理 POST 请求,路径为 /items/
  • @app.put("/items/{item_id}"):处理 PUT 请求,路径为 /items/{item_id},其中 item_id 是路径参数。
  • @app.delete("/items/{item_id}"):处理 DELETE 请求,路径为 /items/{item_id}

路径和查询参数

  • 路径参数:通过 {} 包裹在路径中定义,函数参数中需要声明匹配的名称和类型。
  • 查询参数:通过 URL 中的 ? 后面指定,函数参数中直接声明即可。

路由分组

app.include_router 用于将多个路由组合在一起的功能。它允许我们将路由分组到不同的模块中,从而使代码更加模块化和可维护。

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
FastAPI_project.
│  server.py
├─ai
│  ├─image
│  │  │  urls.py
│  │  │  __init__.p
│  │
│  ├─music
│  │  │  urls.py
│  │  │  __init__.py

假设你有一个用户相关的 AI 生图和 AI 生成音乐模块 image/urls.pymusic/urls.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

#    两个url文件内容一样
from fastapi import APIRouter

image =APIRouter()  

@image.get("/generate")
def image_generate():

    return{"message": "image_generate"}

然后在主应用中包含这个路由:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# main.py
from fastapi import FastAPI
import uvicorn

# 导入自定义的路由模块
from api.image.urls import image
from api.music.urls import music

# 创建 FastAPI 应用实例
app = FastAPI()

# 包含 image 路由器,设置路由前缀和标签
app.include_router(image, prefix="/image", tags=["image"])

# 包含 music 路由器,设置路由前缀和标签
app.include_router(music, prefix="/music", tags=["music"])

# 仅在直接运行该文件时启动 Uvicorn 服务器
if __name__ == "__main__":
    # 启动服务器,监听 8000 端口,启用自动重载
    uvicorn.run("main:app", port=8000, reload=True)

然后就可以通过 http://localhost:8000/image/generatehttp://localhost:8000/music/generate 分别访问到对应的内容

说明

  • APIRouter:用于创建一个路由器实例,可以定义一组相关的路由。
  • include_router:将路由器实例包含到主应用中。prefix 可以设置路由的前缀,tags 和还没有用到的 summary 参数用于访问 docs 形成的注释,可以试着在浏览器访问http://127.0.0.1:8000/docs
  • 模块化:通过将路由分组到不同模块中,可以更好地组织代码,特别是在大型应用中。

路径参数限制

1
2
3
4
5
6
7
from fastapi import FastAPI, Path

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int ):
    return {"item_id": item_id}

async def read_item(item_id: int ): 中的 item_id: int 相当于限制住了这个参数,一定要为 int 类型,否则如果是 str 类型会出现,响应返回非法类型的错误

查询参数限制

type hints 主要是要指示函数的输入和输出的数据类型, 数据类型在 typing 包中, 基本类型有 str list dict 等等, Union 是当有多种可能的数据类型时使用, 比如函数有可能根据不同情况有时返回 str 或返回 list, 那么就可以写成 Union[list, sttr]

Optional 是 Union 的一个简化, 当数据类型中有可能是 None 时, 比如有可能是 str 也有可能是 None, 则 Optional[str], 相当于 Union[str, None]