FastAPI介绍
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.8+ 并基于标准的 Python 类型提示。
FastAPI 主要依赖:
官方文档: fastapi.tiangolo.com/zh/
fastapi、django、flask github热度对比
框架 | Star | 开源地址 |
---|---|---|
django | 76.7k | github.com/django/djan… |
flask | 66.3K | github.com/pallets/fla… |
fastapi | 70.9K | github.com/tiangolo/fa… |
据长期观察,FastAPI start数量是增长速度最快的一个。
安装
pip install fastapi
#还会需要一个 ASGI 服务器
pip install "uvicorn[standard]"
可选依赖
用于 Pydantic:
- email_validator - 用于 email 校验。
用于 Starlette:
- httpx - 使用 TestClient 时安装。
- jinja2 - 使用默认模板配置时安装。
- python-multipart - 需要通过 request.form() 对表单进行「解析」时安装。
- itsdangerous - 需要 SessionMiddleware 支持时安装。
- pyyaml - 使用 Starlette 提供的 SchemaGenerator 时安装(有 FastAPI 你可能并不需要它)。
- graphene - 需要 GraphQLApp 支持时安装。
用于 FastAPI / Starlette:
你可以通过 pip install "fastapi[all]" 命令来安装以上所有依赖。
start-demo
使用
- 创建一个 main.py 文件并写入以下内容:
from typing import Union
# 1.导入 FastAPI
from fastapi import FastAPI
from pydantic import BaseModel
#2.创建一个 FastAPI
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Union[bool, None] = None
# 创建路径操作
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
启动
#启动命令
uvicorn main:app --reload
#看到这个说明正常启动
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
uvicorn main:app 命令含义如下:
- main:main.py 文件(一个 Python「模块」)。
- app:在 main.py 文件中通过 app = FastAPI() 创建的对象。
- --reload:让服务器在更新代码后重新启动。仅在开发时使用该选项。
打开浏览器访问 http://127.0.0.1:8000
Api文档
swagger Ui 方式: http://127.0.0.1:8000/docs
redoc方式: http://127.0.0.1:8000/redoc
可以通过http://127.0.0.1:8000/openapi.json 查看项目的所有接口数据结构
使用指南
支持的路径操作
- POST:创建数据
- GET:读取数据
- PUT:修改数据
- DELETE:删除数据
- OPTIONS
- HEAD
- PATCH
- TRACE
可使用参数:
- tags 用于添加标签;
- status_code 用于响应中的 HTTP 状态码;
- summary:接口概述;
- description:接口详细描述
- response_description:响应描述
- deprecated:废弃接口
路径参数
from fastapi import FastAPI
app = FastAPI()
// me是user_id的一种
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
/users/{user_id}
中的{user_id}
就是路径参数
注意: 由于路径操作是按顺序依次运行的,因此,一定要在 /users/{user_id}
之前声明 /users/me
。否则,/users/{user_id}
将匹配 /users/me
,FastAPI 会认为正在接收值为 "me" 的 user_id 参数。
保安路径的路径参数:
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
/files/{file_path:path}
中的file_path是一个路径参数,:path说明file_path应匹配路径
查询参数
from fastapi import FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
return fake_items_db[skip : skip + limit]
访问:http://127.0.0.1:8000/items/?skip=0&limit=10
为不是路径参数的参数声明默认值,该参数就可选的了。
如果只想把参数设为可选,则要把默认值设为 None。
如果要把查询参数设置为必选,就不要声明默认值。
请求体
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
与声明查询参数一样,包含默认值的模型属性是可选的,否则就是必选的。默认值为 None 的模型属性也是可选的。
参数描述和校验
这个如果使用过swagger的话,可以很好理解。这里值举个字符串的例子:
from typing import Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Union[str, None] = Query(
default=None, #参数默认值,None标识可选,如果是必选,改为Required或...
alias="item-query", #参数别名
title="Query string", # 参数标题
description="Query string", #参数说明
min_length=3, #字符串类型的数据长度校验
max_length=50,#字符串类型的数据长度校验
pattern="^fixedquery$", # 字符串类型正则匹配
deprecated=True, #表明参数弃用
),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
- Query 处理查询参数及校验
- Path 处理路径参数及校验
- Body:表明参数是请求体的一部分
- Field:声明在模型上
响应模型
response_model 参数来定义响应模型
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list[str] = []
@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
return item
@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
return [
{"name": "Portal Gun", "price": 42.0},
{"name": "Plumbus", "price": 32.0},
]
请求文件
# 需要先安装
pip install python-multipart
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
File适合小型文件
UploadFile:更适于处理图像、视频、二进制文件等大型文件
错误处理
FastAPI 自带了一些默认异常处理器。触发 HTTPException 或请求无效数据时,这些处理器返回默认的 JSON 响应结果。不过,也可以使用自定义处理器覆盖默认异常处理器。
覆盖默认异常处理器时需要导入 RequestValidationError,并用 @app.excption_handler(RequestValidationError) 装饰异常处理器。
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return PlainTextResponse(str(exc), status_code=400)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 3:
raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
return {"item_id": item_id}