fastapi针对前后端分离的api操作做了相当多的订制,对于体现在入参、返回值以及异常处理上。
传入的参数可以有三种,路径参数,查询参数以及请求体。
参数的自动匹配,类型转换:
传统的web开发,需要开发同学自己从request.GET/POST里按字段去取值,然后自己转换类型。
fastapi直接把这些值取出来,并转到位,尤其是可以生成类(结构体),直接访问就好。
请求体
class Extra(BaseModel):
message: Union[None, str] = None
# 请求体
class Extra2(BaseModel):
message2: Union[None, str] = None
# 按约定,username自动识别为path, password自动识别为query
@router.post('/hello/{username}')
def hello(username: str, password: str, data: Extra, data2: Extra2):
return {
'username': username,
'password': password,
'data': data,
'data2': data2
}
常用的基本就够了,还是header参数,cookie参数等,都可以自动匹配取出来。
这里相比传统的django, flask框架,就是少了从request里读参数,判断类型,数据校验的问题。
下面说说错误处理。
fastapi推荐的HttpException在开发中不太实用,只要是接口正常,http_status_code都是200,然后在返回值里体现:
{
code: 0 服务正常/ -1 一般错误(参数错。。。)/ 1401 认证问题 / .....
msg: '错误描述'
data: 业务返回值可以是json,如 {page:1,count:10,list:[]}
}
可以拦截RequestValidationError,然后返回我们自定义的反馈,接口状态还是200, 通过
code, message, data来表明具体错误原因。
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""
捕获请求参数 验证错误
:param request:
:param exc:
:return:
"""
# logger.error(f"参数错误\nURL:{request.url}\nHeaders:{request.headers}\n{traceback.format_exc()}")
# print(traceback.format_exc())
return JSONResponse(
status_code=status.HTTP_200_OK,
content=jsonable_encoder({"code": 10002, "message": "参数不全或参数错误",
"data": {"tip": exc.errors()}, "body": exc.body,
}),
)
最后是响应模型,通过response_model参数来设定。
通过HelloOut这个模型,可以过滤掉原来的字段,比如原来返回一个user类,要把password过滤掉就特别有用,同样,这个模型里设定的字段默认都是必填的,这就确保接口需要有正确的返回。
class HelloOut(BaseModel):
username: str
password: str
user_id: int
# 按约定,username自动识别为path, password自动识别为query, data, data2自动识别为Body
@router.post('/hello/{username}', response_model=HelloOut)
def hello(uid: int, username: str, password: str, data: Extra, data2: Extra2,
start_datetime: Union[datetime, None] = Body(default=None),
):
return {
'uid': uid,
'username': username,
'password': password,
'data': data,
'data2': data2,
'start_dt': start_datetime,
'user_id':123
}
todo: 这里response_model如果校验错误,会返回500错误,如何拦截下来,并使用我们自定义的response的内容,待补充。
一个接口的基本使用就是这样,相比传统的api开发,就是输入参数不用自己管了,效率高且不容易出错,就是这样。