FastAPI-响应处理和配置

前篇学习了关于请求参数相关的约束验证, Request

包括 路径参数 , 查询参数, 枚举参数, 文件参数, 类型验证, 多参数嵌套验证, 请求体嵌套验证, Cookie 和 Header 等, 了解完这些对于接口的请求基本就到位了.

这篇便主要针对响应处理进行介绍 Response

项目结构

主要来自慕课网的学习公开课笔记, 目录结构如下:

base

  • __ init __.py
  • base_01.py
  • base_02.py
  • base_03.py
  • base_04.py
  • ...

main.py

其中 main.py 的内容如下:

from fastapi import FastAPI
import uvicorn 

from base import app01
from base import app02
from base import app03
from base import app04


app = FastAPI(
  title="FastAPI 基础教程",
  version='1.0.0',
  docs_url='/docs'
)

app.include_router(app01, prefix='/app01', tags=['请求参数和验证'])
app.include_router(app02, prefix='/app02', tags=['响应处理和配置'])
app.include_router(app03, prefix='/app03', tags=['依赖注入和系统'])
app.include_router(app04, prefix='/app04', tags=['安全认证和授权'])


if __name__ == '__main__':
  uvicorn.run('main:app', host='0.0.0.0', port=8000, reload=True, workers=1)

响应体处理 Response

对应的资源引入, 主要是表达, 文件上传, 异常类, 模型类, 类型校验等如下:

# app02.py

from fastapi import APIRouter, status, Form, File, UploadFile, HTTPException
from typing import Optional, List, Union 
from pydantic import BaseModel, EmailStr


app02 = APIRouter()

响应模型类 response_model

演示用一个常用的用户信息类, 包含用户的姓名, 昵称, 电话, 邮箱, 地址等

# 用户信息基类 (共有)
class User(BaseModel):
  username: str
  email: EmailStr       # pip install pydantic[email]
  mobile: str = '10086' # 真实项目中, 可用 Field 做正则校验
  full_name: Optional[str] = None 
  address: str = None 

# 用户信息输入类, 会多输入一个密码
class UserIn(User):
  password: str 
  
# 用户信息输出类, 不返回密码, 其他都返回
class UserOut(User):
  pass

# 用户数据模拟
users = {
  "user01": { 'username': 'cj', 'password': 123123, 'email': 'user01@example.com' },
  "user02": { 'username': 'youge', 'password': 123456, 'email': 'user02@example.com' }
}

请求用户信息响应, 前端输入是一个post请求 UerIn, 响应的模型是 UserOut .

@app02.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, "密码不会被返回的")
  return users['user01']

响应属性:

@app02.post('/response_model/attributes', 
            # response_model=UserOut
            # response_model=Union[UserIn, UserOut]
            response_model=List[UserOut]
            # response_model_include=['username', 'email'],
            # response_model_exclude=['mobile']
            )
            

可以进行合并, 选择等灵活操作. 比如我们要返回 UserIn 和 UserOut 但密码不返回, 也是可以取巧处理的.

async def response_model_attributes(user: UserIn):
  # Union[UserIn, UserOut] 后, 删掉 password 也能返回成功的
  del user.password
  return [user, user]

响应状态码 status

查看它的源码其实就是对类似 200, 404, 500 等响应码进行语义化而已, 其实也多此一举我觉得.

@app02.post('/status_code', status_code=200)
async def status_code():
  return { 'status_code': 200 }


@app02.post('/status_attribute', status_code=status.HTTP_200_OK)
async def status_attribute():
  print(type(status.HTTP_200_OK))
  return { 'status_code': status.HTTP_200_OK }

这里的 status.HTTP_200_OK, 其实就是数字 200.

表单数据处理 Form

请求和响应都经常会用到, 最多的就是注册, 登录相关,

注意这里用 Form 类则需要 pip install python-multipart

@app02.post('/login')
async def login(username: str = Form(...), password: str = Form(..., regex='^a')):
    
  # Form 类的校验方法类似 Path, Query, Cookie, Header 等

  # 走完认证逻辑后, 返回用户名
  return { 'username': username }


curl -X 'POST' \
  'http://127.0.0.1:8000/app02/login' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'username=admin&password=admin'

单/多/大文件上传处理 File, UploadFile

@app02.post('/file')
async def file(file: bytes = File(...)):
# async def file(file: List[bytes] = File(...)):
  """使用 File 类, 文件内容会议 bytes 形式读入内存, 适合小文件上传"""
  return { 'file_size': len(file) }


@app02.post('/upload_files')
async def upload_files(files: List[UploadFile] = File(...)):
  """
  使用 UploadFile 类的优势:
    1. 文件优先存在内存, 如果达到阈值后, 将被保存在磁盘中
    2. 适合于图片, 视频等大文件
    3. 可以获取上传文件的元数据, 如文件名, 创建时间等
    4. 有文件对象的异步接口
    5. 上传的文件是 Pyhon 文件对象, 可以使用 write(), read(), seek(), close() 等操作

  """
  for file in files:
    contents = await file.read()
    print('文件的内容是: ', contents)
  
  return { 'filename': files[0].filename, 'content_type': files[0].content_type }

接口文档配置

@app02.post(
  '/path_operation_configuration',
  response_model=UserOut,
  # tags=["Path", "Operation", "Configuration"],
  summary="This is summary",
  description="这是一个描述哈",
  response_description="给前端响应一个描述",
  deprecated=True,
  status_code=status.HTTP_200_OK
)
async def path_operation_configuration(user: UserIn):
  """
  路径操作配置
    请求: 用户信息
    响应: 返回结果

  """
  return user

应用文档配置

# main.py 

app = FastAPI(
  title="FastAPI 基础教程",
  version='1.0.0',
  docs_url='/docs'
)

异常类处理 HTTPException

这些都是很常见的操作了, 简单粗暴.

@app02.get('/http_exception')
async def http_exception(city: str):
  if city != 'Beijing':
    raise HTTPException(status_code=404, headers={ "X-Error": "Error" }, detail="City not found")
  return { 'city': city }

这样关于响应模块的也就基本差不多了, 当然在实际应用中, 响应要怎么弄其实都看自己灵活配置, 重点还是请求校验这块更为关键哦.

posted @ 2023-12-14 23:24  致于数据科学家的小陈  阅读(45)  评论(0编辑  收藏  举报