FastAPI 教程(七)

異常處理

異常處理需要先從 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() 裝飾器來自定義異常處理器帖渠,處理器函數(shù)需要有兩個參數(shù)谒亦,一個是 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裝飾器中把異常類作為參數(shù),就可以覆寫異常類的默認處理方法了狞甚,例如:

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 來編碼數(shù)據(jù)

使用 fastapi.encoders 中的 jsonable_encoder 可以把數(shù)據(jù)編碼成 json 格式哼审,并自動做一些類型轉(zhuǎn)換鄙漏,比如把 python 中的日期型轉(zhuǎn)成字符串,例如:

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

整體更新與部分更新

我們在更新的時候棺蛛,如果參數(shù)的類定義中有默認值怔蚌,而傳入的參數(shù)中為指定明確的值,則生成的對象就會使用默認值旁赊,從而對數(shù)據(jù)進行整體更新桦踊,例如:

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 參數(shù):

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

在更新這三個字段的同時,還會把 tax 更新程默認的 10.5 终畅,這是不符合我們需求的籍胯。

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

使用 Pydantic 中的 .dict() 方法离福,降參數(shù) 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
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绿聘,隨后出現(xiàn)的幾起案子嗽上,更是在濱河造成了極大的恐慌,老刑警劉巖熄攘,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兽愤,死亡現(xiàn)場離奇詭異,居然都是意外死亡挪圾,警方通過查閱死者的電腦和手機浅萧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哲思,“玉大人惯殊,你說我怎么就攤上這事∫仓常” “怎么了土思?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長忆嗜。 經(jīng)常有香客問我己儒,道長,這世上最難降的妖魔是什么捆毫? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任闪湾,我火速辦了婚禮,結(jié)果婚禮上绩卤,老公的妹妹穿的比我還像新娘途样。我一直安慰自己,他們只是感情好濒憋,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布何暇。 她就那樣靜靜地躺著,像睡著了一般凛驮。 火紅的嫁衣襯著肌膚如雪裆站。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天黔夭,我揣著相機與錄音宏胯,去河邊找鬼。 笑死本姥,一個胖子當著我的面吹牛肩袍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播婚惫,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼氛赐,長吁一口氣:“原來是場噩夢啊……” “哼魂爪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鹰祸,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤甫窟,失蹤者是張志新(化名)和其女友劉穎密浑,沒想到半個月后蛙婴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡尔破,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年街图,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懒构。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡餐济,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胆剧,到底是詐尸還是另有隱情絮姆,我是刑警寧澤,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布秩霍,位于F島的核電站篙悯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铃绒。R本人自食惡果不足惜鸽照,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颠悬。 院中可真熱鬧矮燎,春花似錦、人聲如沸赔癌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灾票。三九已至浅乔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铝条,已是汗流浹背靖苇。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留班缰,地道東北人贤壁。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像埠忘,于是被迫代替她去往敵國和親脾拆。 傳聞我的和親對象是個殘疾皇子馒索,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350