1. FastAPI 介绍和安装
FastAPI 是一个基于 Python 3.6+ 版本的异步 WEB 应用框架,使用 Python 类型注解构建 web API 。它的主要特点如下:
- **高性能:**与 Node JS 和 Go 相当。
- **编码快:**将开发功能的速度提高 2~3 倍。
- **Bug少:**减少大约 40% 的由开发人员导致的错误。
- **直观:**强大的编辑器支持,可智能感知和补全代码。
- **简单:**易于学习和使用,减少文档阅读时间。
- **简短:**尽量减少代码重复。
- **健壮:**获得可用于生产的代码,具有自动交互文档。
- **基于标准:**基于 OpenAPI 和 JSON Schema。
✍ 基于 API 的开放标准 OpenAPI 就是之前被称为 Swagger 的标准。
首先,我们来安装 FastAPI 及其依赖 :
pip install fastapi==0.115.0
在 fastapi 的依赖中,有三个核心依赖:
FastAPI 使用 pydantic 处理所有数据验证、数据序列化以及基于 JSON Schema 的自动模型文档。
Starlette 是一个轻量级的 ASGI 框架 / 工具包,非常适合用 Python 构建异步 Web 服务。FastAPI 就是基于 Starlette 扩展而来的,FastAPI 提供的 Request 请求报文更是直接使用了 Starlette 的 Request 。
✍ FastAPI 基于 Starlette 和 Pydantic 做了很多封装,简化了我们的编码工作。
Uvicorn 是一个轻量级的 ASGI 服务器,基于 uvloop 和 httptools 实现,运行速度极快。我们使用 Uvicorn 来运行 FastAPI 构建的 Web 应用。
✍ ASGI 被称为异步服务器网关接口,和 WSGI 一样,二者都是为 Python 语言定义的 Web 服务器和 Web 应用之间的通用接口。
✍ ASGI 向后兼容了 WSGI,可以认为是 SWGI 的扩展,并且提供异步特性和 WebSocket 支持。
总的来说,FastAPI 框架集众框架之所长,不仅具有 Flask / Django 框架的 Web 核心功能,并且兼具异步特点,具有同步和异步两种运行模式。
✍ 有关 FastAPI 在设计之初从其他 Web 框架中受到的启发详见官网原文。
https://fastapi.tiangolo.com/alternatives/fastapi.tiangolo.com/alternatives/
2. 第一个 FastAPI 应用
2.1 创建并运行一个 web 应用
2.1 创建并运行一个 web 应用
下面,我们创建一个 infer.py 文件,内容如下:
from fastapi import FastAPI #导入fastapi 框架
import uvicorn #异步
#申请FastAPI对象
app=FastAPI()
@app.get("/")
async def index():
return {"msg": "Hello World!"}
@app.get("/items")
async def get_item():
return {"items": "item hello world "}
if __name__ == "__main__":
# fastAPI: app ":fastAPI 是文件名(不含 .py),app 是 FastAPI 实例名
# host = "0.0.0.0":允许外部访问(默认是127.0.0.1,仅本地)
# port = 8000:指定端口(默认8000)
# reload = True:启用热重载(代码修改后自动重启)
#infer:app,infer指的是当前文件的名称,:app申请的FastAPI对象
uvicorn.run("infer:app",host="127.0.0.1",port=8000,reload=False)
✍ FastAPI 可以同时兼容同步和异步两种运行模式,异步 API 使用 async/await 关键字。
首先,实例化了一个 FastAPI 对象 app ,然后使用 @app.get() 装饰器注册了两个处理 GET 请求的视图函数 index 和 get_item:
- index:处理发往
/的GET请求。 - get_item:访问集合资源
/items中的单个元素。
下面,我们来通过 Uvicorn 来运行上述应用,主要作用用于运行异步 Web 应用程序
#需要安装 pip install uvicorn
uvicorn infer:app
其中 reload 参数可以在代码更新后自动重启服务,在开发时方便我们随时验证 API 。命令行运行结果如下:
3. 读取请求中的各类数据

3.1 路径参数
FastAPI 使用格式化字符串中的 {} 声明路径参数,即 URL 变量。比如上文用到的 get_item 视图函数对应的 URL 规则中就使用了路径变量 item_id 。
from fastapi import FastAPI #导入fastapi 框架
import uvicorn #异步
#申请FastAPI对象
app=FastAPI()
#get请求{item_id} 表示变量
@app.get("/items/{item_id}")
async def get_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
if __name__ == "__main__":
# fastAPI: app ":fastAPI 是文件名(不含 .py),app 是 FastAPI 实例名
# host = "0.0.0.0":允许外部访问(默认是127.0.0.1,仅本地)
# port = 8000:指定端口(默认8000)
# reload = True:启用热重载(代码修改后自动重启)
#infer:app,infer指的是当前文件的名称,:app申请的FastAPI对象
uvicorn.run("2:app",host="127.0.0.1",port=8000,reload=False)
http://127.0.0.1:8000/items/3 使用浏览器调用

URL 变量 item_id 的值会作为参数 item_id 传递到视图函数 get_item() 。
此外,参数 item_id 使用了标准的 Python 类型注解,标注类型为 int;FastAPI 将利用类型检查自动完成请求解析,将 item_id 转换为整型。
如果类型转换失败,将返回 422 错误响应:

字符串 hello 无法被转换为整型,因此类型校验失败,返回的错误消息也清晰地指出了这一点,还是非常友好的。
最后,我们需要了解一下路由的匹配顺序:
路由匹配是按顺序进行的,这意味着如果某个静态的 URL 刚好可以匹配到另一个动态的 URL 规则,为了能够正确触发静态 URL 规则对应的视图函数,应确保该 URL 在动态 URL 规则之前声明。
比如:一个固定 URL 的 /users/me 获取当前用户的数据,还有一个动态路由 /users/{user_id} 获取指定 ID 的用户数据。
我们需要确保 /users/me 路径在 /users/{user_id} 路径之前已声明,否则 /users/{user_id} 也将匹配 users/me 。
@app.get("/users/me")
async def get_user_me():
return {"user_id": "current_user info..."}
@app.get("/users/{user_id}")
async def get_user(user_id: str):
return {"user_id": user_id}
测试运行结果:
get_user_me 被触发:

get_user 被触发:

3.2 查询参数
当视图函数声明不属于 URL 路径参数的其他参数时,FastAPI 将自动解析为 Query 查询参数。
✍ 查询参数即 URL 地址中 ? 之后的一系列用 & 分隔的 key-value 键值对。
比如,下面用于处理集合资源访问的视图函数就定义了两个查询参数:
@app.get("/items/")
async def get_items(skip: int = 0, limit: int = 10):
return {"items": [], "skip": skip, "limit": limit}
查询参数作为 URL 的一部分,默认的类型也为字符串,因此需要借助类型注解转换为 int 类型,FastAPI 将依据注解的类型来验证传入的参数。
访问链接 http://127.0.0.1:8000/items/?skip=20&limit=15 ,可以看到查询参数被正确解析到了视图函数的关键字参数中。

此外,因为我们在定义视图函数时,为查询参数 skip 和 limit 指定了默认值,因此查询参数将变为可选的,缺省时将使用默认值。

当定义一个必须指定的查询参数时,就不能再为这个参数定义任意的默认值。
@app.get("/items/{item_id}")
async def get_item(item_id: int, q: str):
return {"item_id": item_id, "q": q}
当未指定查询参数 q 时,将收到 FastAPI 返回的错误响应,提示我们 q 为必须的查询参数。

最后,有关查询参数的类型转换,我们来补充一个示例:
@app.get("/items_bool/{item_id}")
async def get_item(item_id: int, q: str = None, short: bool = False):
item = {"item_id": item_id}
if q:
item.update({'q': q})
item.update({'short': short})
return item
其中,查询参数 short 是一个布尔类型的变量,默认值为 False 。在交互式文档中,我们可以清晰地看到 short 和 q 两个查询参数都是可选的,并且 short 变量类型为布尔型。
3.3 请求体数据
定义请求体需要使用 pydantic 模型,不能通过 GET 请求发送请求体。发送请求体时必须通过以下方法:
- PSOT
- PUT
- DELETE
- PATCH
下面,我们使用 pydantic 模块提供的 BaseModel 创建一个数据模型类:
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
width: float
height: float
和查询参数类似,模型类中定义的属性字段如果不是必需字段的话,可以设定默认值;否则该字段就是必须的。
接下来,我们只需要在视图函数的参数列表中,将参数的类型注解为模型类 Item 即可:
上面的输入使用postman传入参数

FastAPI 将按照 JSON 类型的响应读取请求体中的数据,并按照 Item 类中属性的类型注解验证数据类型,验证失败时返回错误字段的位置以及原因。
windows如果出现端口占用怎么杀掉。

浙公网安备 33010602011771号