Гузариш ба мундариҷа
Мавзӯи 5 аз 6

Ҷавобҳо ва хатоҳо

Чаро ҷавобро бояд тарҳрезӣ кард

Ба муштарӣ гирифтани ягон JSON кофӣ нест. Ӯ бояд фаҳмад, ки сабт сохта шуд ё не, дархостро такрор кардан мумкин аст ё не ва ҷавоб умуман тана дорад ё не. Ҷавоби HTTP аз рамзи ҳолат, сарлавҳаҳо ва тана иборат аст. Ин қисмҳо якҷо шартномаи байни сервер ва интерфейсро месозанд.

Барои хатоҳои пешбинишуда рамзҳои устувор ва шакли ягона муфиданд. Он гоҳ frontend мухолифати додаҳоро аз набудани захира фарқ мекунад ва татбиқи дохилиро бе аз нав навиштани муштарӣ тағйир додан мумкин аст. Ҳар мисоли поён мустақил аст; ба ҷойи рӯйхати корҳо масирҳои хурди хидматӣ истифода мешаванд.

Рамзи ҳолат ва HTTPException

200 муваффақияти одӣ, 201 сохтан ва 204 муваффақияти бе танаро маъно медиҳад. 400 дархости нодуруст, 401/403 мушкили шахсият ё ҳуқуқ, 404 набудани захира ва 409 мухолифат бо додаҳои ҷориро нишон медиҳад. FastAPI барои хатоҳои санҷиши вуруд 422 истифода мекунад. Доимиҳои status мақсадро равшан мекунанд. raise коркардро қатъ мекунад, на танҳо объекти хато месозад.

from fastapi import FastAPI, HTTPException, status
from fastapi.testclient import TestClient

app = FastAPI()

@app.post("/lock")
def lock():
    raise HTTPException(status.HTTP_409_CONFLICT, detail={"locked": True})

r = TestClient(app).post("/lock")
print(r.status_code, r.json())

Баромад:

409 {'detail': {'locked': True}}

Истисно ва коркардкунандаи худӣ

Истиснои Python метавонад мушкили соҳаи барномаро бе интихоби шакли HTTP дар ҷойи хато тавсиф кунад. Коркардкунандаи бо @app.exception_handler сабтшуда дархост ва истисноро мегирад. Он JSONResponse-и тайёр бармегардонад: status_code рамзи воқеӣ ва content додаҳои танаро медиҳад. Дар поён коркардкунанда мушкили анборро ба ҷавоб бо шакли худ табдил медиҳад.

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

class StockError(Exception):
    def __init__(self, available: int):
        super().__init__(available)
        self.available = available

app = FastAPI()

@app.exception_handler(StockError)
def stock_error(request: Request, exc: StockError):
    return JSONResponse(status_code=409, content={"available": exc.available})

@app.post("/reserve")
def reserve():
    raise StockError(0)

r = TestClient(app).post("/reserve")
print(r.status_code, r.json())

Баромад:

409 {'available': 0}

Сарлавҳаҳо бо ҷавоби одии JSON

Параметри response: Response объектеро барои танзими ҷавоби оянда медиҳад. Метавон сарлавҳа навишта, луғати одӣ баргардонд: FastAPI танзимҳоро бо танаи JSON якҷо мекунад. Сарлавҳаҳо маълумоти иловагӣ, масалан муҳлати кеш ё суроғаи захираи навро мебаранд. Location дар ҷавоби 201 одатан ҳамин суроға аст. Дар поён сарлавҳаи худии версияро мегузорем.

from fastapi import FastAPI, Response
from fastapi.testclient import TestClient

app = FastAPI()

@app.get("/version")
def version(response: Response):
    response.headers["X-Revision"] = "7"
    return {"revision": 7}

r = TestClient(app).get("/version")
print(r.status_code, r.headers["X-Revision"], r.json())

Баромад:

200 7 {'revision': 7}

Ҷавоби бе тана

204 No Content маънои набудани танаро дорад. Барои ошкор ифода кардани он Response(status_code=204) баргардонед. Муштарӣ набояд барои чунин ҷавоб json() даъват кунад: ҳатто JSON-и null ҳам муҳтаво аст, вале дар ин ҷо байт нест. content дар TestClient имкон медиҳад дарозии танаро рост санҷед.

from fastapi import FastAPI, Response
from fastapi.testclient import TestClient

app = FastAPI()

@app.delete("/cache", status_code=204)
def clear():
    return Response(status_code=204)

r = TestClient(app).delete("/cache")
print(r.status_code, len(r.content), repr(r.content))

Баромад:

204 0 b''

Рақам ба андозаи маҷмӯа баробар нест

Пас аз нест кардани сабти миёна len(records) + 1 метавонад бо рақами мавҷуд мувофиқ ояд. Ҳисобкунаки афзоянда аз андозаи луғат вобаста нест. itertools.count тавассути next қиматҳои пайдарпай медиҳад. Мисол принсипро бе масир нишон медиҳад. Дар барномаи доимии чандравандӣ рақамҳои ягонаро одатан пойгоҳи додаҳо медиҳад, на тағйирёбандаи маҳаллии Python.

from itertools import count

records = {1: "A", 3: "C"}
print(len(records) + 1 in records)
ids = count(4)
print(next(ids), next(ids))

Баромад:

True
4 5

Дар дохил чӣ рӯй медиҳад

FastAPI натиҷаи одии масирро ба JSON табдил дода, танзимҳои ҷавобро татбиқ мекунад. Объекти тайёри Response аллакай ҷавоби HTTP дорад ва мустақим баргардонда мешавад: филтри худкори response_model ба танаи он татбиқ намешавад. Ба чунин ҷавоб додаҳоеро нагузоред, ки модел бояд пинҳон мекард.

Истиснои ба вуҷудомада ба роҳи коркарди хатоҳо меравад. Коркардкунандаи сабтшудаи навъи мувофиқ онро ба ҷавоб табдил медиҳад. Ин ба тарҷумон монанд аст: мантиқи соҳа мушкилро бо истилоҳҳои худ мегӯяд ва коркардкунанда протоколи ба муштарӣ фаҳморо месозад. Матни JSON ва рамзи HTTP мустақиланд: танҳо майдони "code": 409 ҳолати 409 намегузорад.

Хатоҳои маъмул ва ислоҳи онҳо

  1. return {"error": 404} бо пешфарз ҷавоби муваффақи 200 мемонад. Барои радкунии пешбинишуда истисно ё status_code-и ошкор истифода кунед.
  2. JSONResponse({"code": 409}) бе status_code=409 рамзи одии 200 мефиристад. Рамзро аз муҳтаво алоҳида гузоред.
  3. r.json() барои ҷавоби 204 кӯшиши таҷзияи холигӣ аст. Рамз ва r.content-ро санҷед; JSON-ро танҳо дар ҷое хонед, ки ваъда шудааст.
  4. new_id = len(records) + 1 пас аз несткунӣ такрори рақамро иҷозат медиҳад. Ҳисобкунаки афзоянда ё ҳангоми кор бо пойгоҳи додаҳо механизми калидҳои онро истифода кунед.

Ёддошт

Ҳолат Восита
Сохтан / муваффақияти бе тана / мухолифат 201 / 204 / 409
Радкунии пешбинишуда raise HTTPException(...)
Шакли умумии хатоҳои худӣ @app.exception_handler(ErrorType)
Ҷавоби тайёри JSON JSONResponse(status_code=..., content=...)
Иловаи маълумоти иловагӣ response.headers["Name"] = "value"
Танаи холӣ Response(status_code=204)