Pydantic
pydantic是一个数据验证的库,FastAPI使用它来做模型校验。
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None
app = FastAPI()
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
Item
是个入参模型,它的name必须str类型,price必须float类型,is_offer是可选的,可以为bool类型或不传。像下图这样是可以通过验证的。
PUT <http://127.0.0.1:8000/items/6>
{
"name": "dongfanger",
"price": 2.3,
"is_offer": true
}
请求体
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
继承于BaseModel来自定义Model,FastAPI会自动转换为JSON。
参数设置
路径参数
把路径参数传递给函数,可以指定参数类型:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
效果是访问 http://127.0.0.1:8000/items/foo 会返回{"item_id":"foo"}
。指定了Python类型后,FastAPI会强制检查,比如传str会报错,传float也会报错
匹配先后顺序
代码定义的先后顺序会决定匹配结果,比如正常来说,下面的/users/me
会返回{"user_id": "the current user"}
:
from fastapi import FastAPI
app = FastAPI()
@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}
假如这2个path定义顺序反过来,那么/users/me
就会匹配到/users/{user_id}
而返回{"user_id": me}
了。
枚举路径
借助于Enun类,可以实现枚举路径:
from enum import Enum
from fastapi import FastAPI
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
app = FastAPI()
@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
if model_name == ModelName.alexnet:
return {"model_name": model_name, "message": "Deep Learning FTW!"}
if model_name.value == "lenet":
return {"model_name": model_name, "message": "LeCNN all the images"}
return {"model_name": model_name, "message": "Have some residuals"}
这样在docs界面就可以看到一个可以选择的参数输入口了
path匹配
FastAPI提供了一个path类型,可以用来对文件路径进行格式匹配:
from fastapi import FastAPI
app = FastAPI()
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
路径参数数字校验
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(..., title="The ID of the item to get", gt=0, le=1000),
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
路径参数永远都是必填的,因为它是url一部分。...表示必填,就算设置为None也没有用,仍然是必填。
-
ge表示大于等于,greater equal。
-
le表示小于等于,less equal。
-
gt表示大于,greater than。
-
lt表示小于,less than。
查询参数
查询参数是跟在路径参数后面,用?
分隔用&
连接的参数,比如http://127.0.0.1:8000/items/?skip=0&limit=10
。
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
return fake_items_db[skip : skip + limit]
参数是可选的并且设置了默认值:limit: int = 10
参数是可选的,无默认值:limit: Optional[int] = None
是否可选是由None来决定的,而Optional只是为编译器提供支持,跟FastAPI没有关系。
参数是必填的:limit: int
Query参数校验
Query Parameters and String Validations - FastAPI (tiangolo.com)
FastAPI提供了Query来支持对入参的字符串校验,比如最小长度和最大长度,甚至其中也能包含正则表达式:regex="^fixedquery$"
。:
from typing import Optional
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
Query的第一个参数可以为该参数指定一个默认值,此处传None即为不指定默认值。而如果传 ...
的话,则意味必须填写这个参数。
实战
利用fastapi返回文件
from starlette.responses import FileResponse
from fastapi import FastAPI
app = FastAPI()
async def get_transfer(file_path):
if not os.path.exists(filepath):
return 'no such files!'
headers = {
"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
return FileResponse(filepath, filename='{}.csv'.format(file_name), headers=headers)
Fastapi文档的编写
fastapi提供两种api文档,:
- 交互式API文档:
在浏览器中请求 http://127.0.0.1:8000/docs即可(由 Swagger UI 提供)
- 备用API文档
在浏览器中请求 http://127.0.0.1:8000/redoc,显示备用API文档(由 ReDoc提供)
FastAPI接口文档注释
-
title 标题
-
description 描述,用以详细介绍api
-
summary 注释,用以简单介绍api
-
tags 标签,用以将api分类排列
from fastapi import FastAPI
app = FastAPI(title='第一个Fast API应用程序', description='整体描述')
@app.get(path='/', summary='接口注释', description='接口描述', tags=['Root'])
async def read_root():
return {"Hello": "World"}
显示效果如下:
也可以不使用summary进行接口注释,用多行注释取而代之,格式为markdown
from fastapi import FastAPI
app = FastAPI()
@app.get(path='/items/{item_id}', summary='接口注释', tags=['Items'])
async def read_item(item_id: int, q: str = None):
'''
项目
- param item_id: 项目ID
- param q: 查询参数
- return: 以给定项目ID和参数为数据的对象,字段为item_id,q
'''
return {"item_id": item_id, "q": q}
显示效果如下:
其他零碎的整理
fastapi传输文件
Content-Type用来定义用户的浏览器或其他设备如何显示将要加载的数据,或将要如何处理将要加载的数据。
Content-Type 一般以下面的形式出现:
Content-Type:[type]/[subtype];parameter
type 有以下的类型:
-
Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的
-
Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据
-
Application:用于传输应用程序数据或者二进制数据
-
Message:用于包装一个E-mail消息
-
Image:用于传输静态图片数据
-
Audio:用于传输音频或者音声数据
-
Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式
subtype 用于指定type的详细形式。下面是常用到MIME类型:
-
text/html(HTML 文档)
-
text/plain(纯文本)
-
text/css(CSS 样式表)
-
image/gif(GIF 图像)
-
image/jpeg(JPG 图像)
-
application/x-javascript(JavaScript 脚本)
-
application/x-shockwave-flash(Flash)
-
application/x- www-form-urlencoded(使用 HTTP 的 POST方法提交的表单)
-
multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)
因此最开始遇到的那个问题是因为浏览器没有正确处理excel文件,因为Content-Type为text/plain。手动为接口添加能处理excel文件的Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
import fastapi import FastApi
From starlette.responses import FileResponse
app = FastApi()
@app.get("/File")
async def get_file():
filepath = "./data/demo.xlsx"
filename = "demo.xlsx"
headers = {
"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
return FileResponse(filepath, filename=filename, headers=headers)
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000, debug=True)
更多拓展名可以看这个网站 MIME 参考手册 (w3school.com.cn)
[文章导入自 http://qzq-go.notion.site/683d71c90aac436dbdfef9c3ad31df48 访问原文获取高清图片]