美文网首页
FastAPI 教程(七)

FastAPI 教程(七)

作者: Frederich | 来源:发表于2020-07-13 16:56 被阅读0次

异常处理

异常处理需要先从 fastapi 中引入 HTTPException,有异常的时候就 raise 一个 HTTPException 对象,该对象有一些属性,包括status_code、detail等,例如:

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}


@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items[item_id]}

建立 HTTPException 对象的时候还可以加入自定义的头,比如:

raise HTTPException(
    status_code=404,
    detail="Item not found",
    headers={"X-Error": "There goes my error"},
)

自定义异常处理器

可以使用 @app.exception_handler() 装饰器来自定义异常处理器,处理器函数需要有两个参数,一个是 request 对象,一个是异常类的对象,例如:

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse


class UnicornException(Exception):
    def __init__(self, name: str):
        self.name = name


app = FastAPI()


@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}
    )


@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
    if name == "yolo":
        raise UnicornException(name=name)
    return {"unicorn_name": name}

覆写默认的异常处理方法

我们可以从 fastapi.exceptions 中引入相应的异常类,然后再 @app.exception_handler装饰器中把异常类作为参数,就可以覆写异常类的默认处理方法了,例如:

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}

此时再去访问 http://localhost:8000/items/foo 就不会得到一个 JSON 的报错信息,而是得到一个纯文本的报错消息。

使用 jsonable_encoder 来编码数据

使用 fastapi.encoders 中的 jsonable_encoder 可以把数据编码成 json 格式,并自动做一些类型转换,比如把 python 中的日期型转成字符串,例如:

from datetime import datetime
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

fake_db = {}


class Item(BaseModel):
    title: str
    timestamp: datetime
    description: str = None


app = FastAPI()


@app.put("/items/{id}")
def update_item(id: str, item: Item):
    json_compatible_item_data = jsonable_encoder(item)
    fake_db[id] = json_compatible_item_data
    print(json_compatible_item_data)
    print(type(json_compatible_item_data))
    return fake_db

整体更新与部分更新

我们在更新的时候,如果参数的类定义中有默认值,而传入的参数中为指定明确的值,则生成的对象就会使用默认值,从而对数据进行整体更新,例如:

from typing import List, Optional
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
    update_item_encoded = jsonable_encoder(item)
    items[item_id] = update_item_encoded   # 这种方式就是整体更新
    return update_item_encoded

此时如果我们传入这样的 json 参数:

{
    "name": "Barz",
    "price": 3,
    "description": None,
}

在更新这三个字段的同时,还会把 tax 更新程默认的 10.5 ,这是不符合我们需求的。

部分更新,使用 .dict(exclude_unset=True)

使用 Pydantic 中的 .dict() 方法,降参数 exclude_unset 设置为 True,就可以只更新我们给定的字段。通常在这种情况下,我们会使用 PATCH 请求而不是 POST 请求,不过其实是都可以的。

from typing import List, Optional
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.patch("/items/{item_id}", response_model=Item)  # 这里也可以用 post
async def update_item(item_id: str, item: Item):
    stored_item_data = items[item_id]
    stored_item_model = Item(**stored_item_data)
    update_data = item.dict(exclude_unset=True)
    updated_item = stored_item_model.copy(update=update_data)  # 拷贝一份出来更新
    items[item_id] = jsonable_encoder(updated_item)
    return updated_item

相关文章

  • FastAPI 教程(七)

    异常处理 异常处理需要先从 fastapi 中引入 HTTPException,有异常的时候就 raise 一个 ...

  • SqlAlchemy:'users' 中的列 'email' 的

    最近在学fastapi,使用的数据库是SQL Server在FastApi官方教程的SQL Database章节[...

  • FastAPI 教程(四)

    参数校验 基本的类型验证可以通过指定参数类型来实现。 如果需要更复杂的校验,就需要引入 fastapi 的 Que...

  • FastAPI 教程(五)

    Body Field 校验 检验可以写在路由方法中,用 Query、Body、Path 等方法来写入校验条件,也可...

  • FastAPI 教程(六)

    Cookie 变量 从 fastapi 引入 Cookie 后,可以使用类似 Query、Path 的方式来获取 ...

  • FastAPI 教程(三)

    表单 如果要获取表单的数据,需要进行一下步骤: 导入 fastapi 中的 Form 在模板中通过 Form(.....

  • FastAPI 教程(一)

    安装 FastAPI 需要安装 fastapi、uvicorn 以及 python-multipart 三个库。 ...

  • FastAPI 教程(二)

    路径参数(Path Parameter) 路径参数在路由里面用大括号括起来,在方法中需要把参数写出来,还可以标注参...

  • fastapi教程翻译(七):Body - 多种参数

    现在我们已经了解了如何使用路径Path和查询Query,让我们来看一下请求主体Body声明的更高级用法。 一、混合...

  • fastapi教程翻译(一):了解FastAPI结构

    一、编写一个简单的FastAPI程序 最简单的FastAPI文件可能如下: 将上面代码块复制到 main.py. ...

网友评论

      本文标题:FastAPI 教程(七)

      本文链接:https://www.haomeiwen.com/subject/wxumcktx.html