请求体和响应体的数据格式通常是不同的,如前端用户给后端服务器传递用户名、邮箱、手机号、密码等信息,后端给前端通常不会返回密码
EmailStr需要额外安装:pip install pydantic[email]
通过路径操作,path operation定义响应体的格式
请求体和响应体有关联的,可以通过定义共同的基类来节省代码
from typing import Optional, List
from pydantic import BaseModel, EmailStr
app04 = APIRouter()
"""Response Model 响应模型"""
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
mobile: str = "10086"
address: str = None
full_name: Optional[str] = None
class UserOut(BaseModel):
username: str
email: EmailStr # 用 EmailStr 需要 pip install pydantic[email]
mobile: str = "10086"
address: str = None
full_name: Optional[str] = None
users = {
"user01": {"username": "user01", "password": "123123", "email": "[email protected]"},
"user02": {"username": "user02", "password": "123456", "email": "[email protected]", "mobile": "110"}
}
@app04.post("/response_model/", response_model=UserOut, response_model_exclude_unset=True)
async def response_model(user: UserIn):
"""response_model_exclude_unset=True表示默认值不包含在响应中,仅包含实际给的值,如果实际给的值与默认值相同也会包含在响应中"""
print(user.password) # password不会被返回
# return user
return users["user01"]
@app04.post(
"/response_model/attributes",
response_model=UserOut,
# response_model=Union[UserIn, UserOut], # 返回两者的并集字段
# response_model=List[UserOut], # 返回结果是多个包括userout类型的列表
response_model_include=["username", "email", "mobile"], # 需要在结果中包含的字段
response_model_exclude=["mobile"] # 需要排除的字段
)
async def response_model_attributes(user: UserIn):
# del user.password # Union[UserIn, UserOut]后,删除password属性也能返回成功
return user
# return [user, user]
from fastapi import Form
@app04.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)): # 定义表单类型,...为必填
"""用Form类需要pip install python-multipart; Form类的元数据和校验方法类似Body/Query/Path/Cookie"""
return {"username": username}
需要导入file和uploadfile,当使用file文件会用2进制形式写入内存,只适合小文件上传,文件太大会爆内存
@app04.post("/file")
# 如果要上传多个文件 files: List[bytes] = File(...)
async def file_(file: bytes = File(...)):
return {"file_size": len(file)}
在docs中可以看到定义了file类型后,请求就变为了form-data,在vue端编写请求的时候,可以参考
上传大文件需要使用uploadfile,使用UploadFile类的优势:
async def upload_files(files: List[UploadFile] = File(...)):
for file in files:
contents = await file.read()
print(contents)
return {"filename": files[0].filename, "content_type": files[0].content_type} # 返回第一个文件的数据
可以看到return输出的文件类型为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
在用python或其它语言时,实现下载excel功能或者是上传,要使用content_type定义类型
@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)
在终端看到的输出就是乱码
https://www.w3school.com.cn/media/media_mimeref.asp 可以看到其它常用格式的content_type
静态文件也属于一种返回的形式,需要配置,在项目根路径新建static文件夹,之后在run.py即运行主文件中挂载,对于fastapi而言,static只是一个独立应用,与fastapi无关
app.mount(self,path,app,name) ,特别注意,只能挂在到FastAPI中不要挂到APIRouter中
from fastapi.staticfiles import StaticFiles
app.mount(path='/static', app=StaticFiles(directory='./static'), name='static')
主要用于响应的描述,响应的数据格式,响应状态码等。
deprecated=True ,用于标注该接口已经废弃掉,但依然可以使用
tags=[‘’,‘’] ,接口的描述,可以添加多个,但是不建议,因为会很混乱
状态码可以在路径中的status_code中定义
from fastapi import status
@app04.post("/status_attribute", status_code=status.HTTP_200_OK)
async def status_attribute():
print(type(status.HTTP_200_OK)) # int类型
return {"返回的内容": "返回200状态码"}
如上,推荐使用status,不建议直接返回数字,因为语义化更明确。执行之后在docs中可以看到相应的code
在主文件中的FastAPI可以配置应用,title标题,description简介,version版本号,docs_url接口测试地址(默认是/docs),redoc_url(不能操作,可以给用户参考用,默认/redocs)
通过 from fastapi import HTTPException
捕获错误
if判断,满足条件后,raise抛出raise HTTPException(status_code=404, detail="City not found!", headers={"X-Error": "Error"})
,headers为在response headers
中插入值
想所有应用都用自定义的错误相应,就要在主文件run.py中配置
from fastapi.exceptions import RequestValidationError # 请求错误校验处理
from fastapi.responses import PlainTextResponse # 文本形式返回response
from fastapi import HTTPException
from starlette.exceptions import HTTPException as StarletteHTTPException # fastapi建立在starlette基础之上,所以与上一项的导入相同
重写http异常处理,其中request必须有,exc是错误
@app.exception_handler(StarletteHTTPException) # 重写HTTPException异常处理器,把原来的错误信息从json改为文本形式
async def http_exception_handler(request, exc):
return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
PlainTextResponse的作用是:返回一些纯文本数据
重写请求验证的错误处理
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return PlainTextResponse(str(exc), status_code=400)
新建路由,验证错误处理
@app04.get("/http_exception/{city_id}")
async def override_http_exception(city_id: int):
if city_id == 1:
raise HTTPException(status_code=418, detail="Nope! I don't like 1.")
return {"city_id": city_id}