1. FastAPI 介绍和安装

FastAPI 是一个基于 Python 3.6+ 版本的异步 WEB 应用框架,使用 Python 类型注解构建 web API 。它的主要特点如下:

  1. **高性能:**与 Node JS 和 Go 相当。
  2. **编码快:**将开发功能的速度提高 2~3 倍。
  3. **Bug少:**减少大约 40% 的由开发人员导致的错误。
  4. **直观:**强大的编辑器支持,可智能感知和补全代码。
  5. **简单:**易于学习和使用,减少文档阅读时间。
  6. **简短:**尽量减少代码重复。
  7. **健壮:**获得可用于生产的代码,具有自动交互文档。
  8. **基于标准:**基于 OpenAPI 和 JSON Schema。

✍ 基于 API 的开放标准 OpenAPI 就是之前被称为 Swagger 的标准。

首先,我们来安装 FastAPI 及其依赖 :

pip install fastapi==0.115.0

fastapi 的依赖中,有三个核心依赖:

  1. Pydantic
  2. Starlette
  3. Uvicorn

FastAPI 使用 pydantic 处理所有数据验证、数据序列化以及基于 JSON Schema 的自动模型文档。

Starlette 是一个轻量级的 ASGI 框架 / 工具包,非常适合用 Python 构建异步 Web 服务。FastAPI 就是基于 Starlette 扩展而来的,FastAPI 提供的 Request 请求报文更是直接使用了 Starlette 的 Request

✍ FastAPI 基于 Starlette 和 Pydantic 做了很多封装,简化了我们的编码工作。

Uvicorn 是一个轻量级的 ASGI 服务器,基于 uvloophttptools 实现,运行速度极快。我们使用 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 请求的视图函数 indexget_item

  1. index:处理发往 /GET 请求。
  2. 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 ,可以看到查询参数被正确解析到了视图函数的关键字参数中。

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

当定义一个必须指定的查询参数时,就不能再为这个参数定义任意的默认值。

@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 。在交互式文档中,我们可以清晰地看到 shortq 两个查询参数都是可选的,并且 short 变量类型为布尔型。

3.3 请求体数据

定义请求体需要使用 pydantic 模型,不能通过 GET 请求发送请求体。发送请求体时必须通过以下方法:

  1. PSOT
  2. PUT
  3. DELETE
  4. PATCH

下面,我们使用 pydantic 模块提供的 BaseModel 创建一个数据模型类:

from pydantic import BaseModel
class Item(BaseModel):
    name: str
    description: str = None
    width: float
    height: float

和查询参数类似,模型类中定义的属性字段如果不是必需字段的话,可以设定默认值;否则该字段就是必须的。

接下来,我们只需要在视图函数的参数列表中,将参数的类型注解为模型类 Item 即可:

上面的输入使用postman传入参数

image.png


FastAPI 将按照 JSON 类型的响应读取请求体中的数据,并按照 Item 类中属性的类型注解验证数据类型,验证失败时返回错误字段的位置以及原因。

windows如果出现端口占用怎么杀掉。

image.png