IlmHamroh
Python kursi/Web backend FastAPI12/16-dars17 daqiqa
Mundarija (22)

20.12-dars: Xatolarni boshqarish

20-QISM — WEB-BACKEND (FastAPI) · 12-dars


1. Kirish va motivatsiya

Har API'da xatolar bo'ladi: resurs topilmaydi, ma'lumot noto'g'ri, ruxsat yetmaydi, kutilmagan nosozlik. Bu darsda xatolarni professional boshqarishni o'rganamiz: izchil, tushunarli xato javoblari, maxsus xato klasslari va global xato ishlovchilari.

Yaxshi xato boshqaruvi — API sifatining belgisi. Foydalanuvchi (mijoz dasturchi) xatoni tushunishi kerak: nima bo'ldi, nima uchun, qanday tuzatish. Tartibsiz yoki noaniq xato — API'ni ishlatishni qiyinlashtiradi. Izchil, hujjatlangan xato — uni oson qiladi.

Real vaziyat. Bir API xatolarni turlicha qaytarardi: biri {"error": "..."}, boshqasi {"message": "..."}, uchinchisi oddiy matn, ba'zan 500 bilan stack trace (maxfiy ma'lumot!). Mijoz har xato uchun boshqacha kod yozishga majbur edi, va stack trace serverning ichki tuzilishini oshkor qildi. Jamoa xato javoblarini standartlashtirdi: har xato {"xato": "...", "kod": "..."} shaklida, global handler bilan. Endi mijoz bir xil xatoni kutadi, ichki xatolar yashirindi. API ishonchli va xavfsiz bo'ldi.

Bu darsda xatolarni — HTTPException, maxsus xato klasslari va global ishlovchilarni o'rganamiz.

Bu darsda:

  • HTTPException chuqurroq (status, detail, headers)
  • Global xato ishlovchisi (exception_handler)
  • Maxsus xato klasslari
  • Validatsiya xatosini o'zgartirish
  • Izchil xato javob shakli
  • 500 va kutilmagan xatolar
  • Xavfsizlik (ichki ma'lumotni yashirish)
  • Amaliy: to'liq xato tizimi

ℹ Misollarda FastAPI TestClient bilan sinaladi.


2. Nazariya — chuqur tushuntirish

2.1. HTTPException chuqurroq

HTTPException — status kod, xabar va sarlavha (20.6 dan):

python
from fastapi import HTTPException

raise HTTPException(
    status_code=404,
    detail="kurs topilmadi",
    headers={"X-Xato-Kodi": "KURS_YOQ"},
)
Parametr Vazifa
status_code HTTP status (404, 403, ...)
detail Xabar (satr yoki dict/list)
headers Qo'shimcha sarlavhalar

HTTPException — kutilgan xatolar uchun (topilmadi, ruxsat yo'q). detail satr yoki tuzilgan (dict) bo'lishi mumkin. FastAPI uni JSON xato javobga aylantiradi ({"detail": ...}).

2.2. Global xato ishlovchisi

@app.exception_handler — ma'lum xato turini butun ilovada bir joyda boshqaradi:

python
from fastapi import Request
from fastapi.responses import JSONResponse

@app.exception_handler(ValueError)
def value_error_handler(request: Request, exc: ValueError):
    return JSONResponse(status_code=400, content={"xato": str(exc)})

Xato ishlovchisi — berilgan tur (ValueError) ko'tarilgan har joyda ishlaydi. Bu xato javobni markazlashtiradi — har endpointda qayta yozish shart emas.

2.3. Maxsus xato klasslari

O'z domeningiz uchun maxsus xato (12-qism, istisnolar):

python
class KursTopilmadi(Exception):
    def __init__(self, kurs_id: int):
        self.kurs_id = kurs_id

@app.exception_handler(KursTopilmadi)
def handler(request: Request, exc: KursTopilmadi):
    return JSONResponse(status_code=404, content={"xato": f"kurs {exc.kurs_id} topilmadi", "kod": "KURS_YOQ"})

@app.get("/kurslar/{kurs_id}")
def kurs(kurs_id: int):
    if kurs_id not in BAZA:
        raise KursTopilmadi(kurs_id)     # toza — domen xatosi

Maxsus xato klassi — domen mantiqini (KursTopilmadi) HTTP tafsilotidan (404, JSON) ajratadi. Endpoint domen xatosini ko'taradi, handler uni HTTP javobga aylantiradi.

2.4. Validatsiya xatosini o'zgartirish

FastAPI validatsiya xatosi (422) shaklini o'zgartirish mumkin:

python
from fastapi.exceptions import RequestValidationError

@app.exception_handler(RequestValidationError)
def validatsiya_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=422,
        content={"xato": "ma'lumot noto'g'ri", "maydonlar": len(exc.errors())},
    )

RequestValidationError — Pydantic validatsiya xatosi 20.5-bob. Uni ushlab, o'z shaklingizga aylantirasiz — barcha validatsiya xatolari izchil.

2.5. Izchil xato javob shakli

Barcha xatolar bir xil shaklda bo'lsin:

python
{
    "xato": "kurs topilmadi",      # o'qiladigan xabar
    "kod": "KURS_YOQ",             # mashina uchun kod
}
Maydon Kim uchun
xato/message Odam (o'qiladigan)
kod/code Mashina (dastur mantiqi)
tafsilotlar Qo'shimcha (ixtiyoriy)

Izchil shakl — mijoz har xatoni bir xil qayta ishlaydi. Xato kodi (KURS_YOQ) — dastur mantiqi uchun (til-mustaqil), xabar — foydalanuvchi uchun.

2.6. 500 va kutilmagan xatolar

Kutilmagan xato (koddagi xato, KeyError) — 500:

python
@app.exception_handler(Exception)
def umumiy_handler(request: Request, exc: Exception):
    # log qil (ichki), lekin foydalanuvchiga umumiy xabar
    return JSONResponse(status_code=500, content={"xato": "ichki server xatosi"})

Kutilmagan xato — 500 Internal Server Error. Foydalanuvchiga umumiy xabar (ichki tafsilotsiz), lekin serverda to'liq log. Bu xavfsizlik — stack trace oshkor qilinmaydi.

2.7. Xavfsizlik (ichki ma'lumotni yashirish)

Xato javobi ichki ma'lumot oshkor qilmasligi kerak:

Xavfli Xavfsiz
Stack trace Umumiy xabar
SQL xatosi matni "ma'lumot xatosi"
Fayl yo'llari Yashiringan
Ichki tuzilma Standart javob

Xato javobi hujumchiga ma'lumot bermasligi kerak: stack trace, baza tuzilishi, fayl yo'llari — bularni yashiriring. Ichki xatolarni serverda log qiling, foydalanuvchiga umumiy xabar bering.

2.8. Xato boshqaruvi qatlamlari

Xato turlari va ularning boshqaruvi:

Xato turi Manba Javob
HTTPException Aniq ko'tarilgan Berilgan status
RequestValidationError Pydantic 422
Maxsus (KursTopilmadi) Domen Handler belgilaydi
Exception (umumiy) Kutilmagan 500 (umumiy)

Xato boshqaruvi qatlam-qatlam: aniq xatolar (HTTPException), domen xatolari (maxsus), validatsiya (422), va oxirida kutilmagan (500). Har qatlam o'z javobini beradi.


3. Tez ma'lumotnoma

python
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError

# aniq xato:
raise HTTPException(status_code=404, detail="topilmadi")

# maxsus xato klassi:
class KursTopilmadi(Exception):
    def __init__(self, kurs_id): self.kurs_id = kurs_id

# global handler:
@app.exception_handler(KursTopilmadi)
def handler(request: Request, exc: KursTopilmadi):
    return JSONResponse(status_code=404, content={"xato": ..., "kod": "KURS_YOQ"})

# validatsiya:
@app.exception_handler(RequestValidationError)
def v_handler(request, exc): ...

# kutilmagan:
@app.exception_handler(Exception)
def u_handler(request, exc):
    return JSONResponse(status_code=500, content={"xato": "ichki xatosi"})

Izchil shakl

{"xato": "<o'qiladigan xabar>", "kod": "<MASHINA_KODI>"}

4. Batafsil misollar

Misollarda FastAPI TestClient bilan sinaladi.

Misol 1 — HTTPException va tuzilgan detail

python
"""HTTPException status/detail/headers; detail satr va dict; xato sarlavhasi; standart JSON xato javobi."""

import warnings
warnings.filterwarnings("ignore")

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

app = FastAPI()

BAZA = {1: "Python", 2: "Go"}


@app.get("/kurslar/{kurs_id}")
def kurs(kurs_id: int):
    if kurs_id not in BAZA:
        raise HTTPException(
            status_code=404,
            detail="kurs topilmadi",
            headers={"X-Xato-Kodi": "KURS_YOQ"},
        )
    return {"id": kurs_id, "nom": BAZA[kurs_id]}


@app.get("/hisobot/{yil}")
def hisobot(yil: int):
    if yil < 2000:
        raise HTTPException(
            status_code=400,
            detail={"xabar": "yil noto'g'ri", "minimal": 2000, "berilgan": yil},
        )
    return {"yil": yil}


def main() -> None:
    client = TestClient(app)

    print("=== 1. Muvaffaqiyatli ===")
    print(f"  /kurslar/1 → {client.get('/kurslar/1').json()}")

    print("\n=== 2. ⚠️ 404 va xato sarlavhasi ===")
    javob = client.get("/kurslar/999")
    print(f"  status {javob.status_code}, detail: {javob.json()['detail']}")
    print(f"  X-Xato-Kodi: {javob.headers.get('X-Xato-Kodi')}")

    print("\n=== 3. Tuzilgan detail (dict) ===")
    javob = client.get("/hisobot/1990")
    print(f"  status {javob.status_code} → {javob.json()['detail']}")

    print("\n=== 4. Standart JSON shakli ===")
    print("  FastAPI HTTPException → {'detail': ...}")
    print("  ⭐ HTTPException — status, detail (satr/dict), qo'shimcha sarlavha")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Muvaffaqiyatli ===
  /kurslar/1 → {'id': 1, 'nom': 'Python'}

=== 2. ⚠️ 404 va xato sarlavhasi ===
  status 404, detail: kurs topilmadi
  X-Xato-Kodi: KURS_YOQ

=== 3. Tuzilgan detail (dict) ===
  status 400 → {'xabar': "yil noto'g'ri", 'minimal': 2000, 'berilgan': 1990}

=== 4. Standart JSON shakli ===
  FastAPI HTTPException → {'detail': ...}
  ⭐ HTTPException — status, detail (satr/dict), qo'shimcha sarlavha

Nima ko'rsatdi: 2.1-bo'lim.

Misol 2 — Maxsus xato klassi va handler

python
"""maxsus xato klassi (KursTopilmadi); exception_handler; domen xatosini HTTP javobga aylantirish; izchil shakl."""

import warnings
warnings.filterwarnings("ignore")

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

app = FastAPI()

BAZA = {1: "Python"}


class KursTopilmadi(Exception):
    def __init__(self, kurs_id: int):
        self.kurs_id = kurs_id


class RuxsatYoq(Exception):
    def __init__(self, amal: str):
        self.amal = amal


@app.exception_handler(KursTopilmadi)
def kurs_topilmadi_handler(request: Request, exc: KursTopilmadi):
    return JSONResponse(
        status_code=404,
        content={"xato": f"kurs {exc.kurs_id} topilmadi", "kod": "KURS_YOQ"},
    )


@app.exception_handler(RuxsatYoq)
def ruxsat_handler(request: Request, exc: RuxsatYoq):
    return JSONResponse(
        status_code=403,
        content={"xato": f"'{exc.amal}' uchun ruxsat yo'q", "kod": "RUXSAT_YOQ"},
    )


@app.get("/kurslar/{kurs_id}")
def kurs(kurs_id: int):
    if kurs_id not in BAZA:
        raise KursTopilmadi(kurs_id)
    return {"id": kurs_id, "nom": BAZA[kurs_id]}


@app.delete("/kurslar/{kurs_id}")
def ochir(kurs_id: int):
    raise RuxsatYoq("o'chirish")


def main() -> None:
    client = TestClient(app)

    print("=== 1. Muvaffaqiyatli ===")
    print(f"  /kurslar/1 → {client.get('/kurslar/1').json()}")

    print("\n=== 2. Maxsus xato (KursTopilmadi) ===")
    javob = client.get("/kurslar/999")
    print(f"  status {javob.status_code} → {javob.json()}")

    print("\n=== 3. Boshqa maxsus xato (RuxsatYoq) ===")
    javob = client.delete("/kurslar/1")
    print(f"  status {javob.status_code} → {javob.json()}")

    print("\n=== 4. Izchil shakl ===")
    print("  har xato: {'xato': '...', 'kod': '...'}")
    print("  ⭐ maxsus xato — domen mantig'ini HTTP tafsilotidan ajratadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Muvaffaqiyatli ===
  /kurslar/1 → {'id': 1, 'nom': 'Python'}

=== 2. Maxsus xato (KursTopilmadi) ===
  status 404 → {'xato': 'kurs 999 topilmadi', 'kod': 'KURS_YOQ'}

=== 3. Boshqa maxsus xato (RuxsatYoq) ===
  status 403 → {'xato': "'o'chirish' uchun ruxsat yo'q", 'kod': 'RUXSAT_YOQ'}

=== 4. Izchil shakl ===
  har xato: {'xato': '...', 'kod': '...'}
  ⭐ maxsus xato — domen mantig'ini HTTP tafsilotidan ajratadi

Nima ko'rsatdi: 2.2, 2.3, 2.5-bo'limlar.

Misol 3 — Validatsiya va kutilmagan xato

python
"""validatsiya xatosini o'zgartirish (RequestValidationError); kutilmagan xato (500); ichki ma'lumotni yashirish."""

import warnings
warnings.filterwarnings("ignore")

from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient
from pydantic import BaseModel

app = FastAPI()


@app.exception_handler(RequestValidationError)
def validatsiya_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=422,
        content={"xato": "kiritilgan ma'lumot noto'g'ri", "kod": "VALIDATSIYA", "maydonlar": len(exc.errors())},
    )


@app.exception_handler(Exception)
def umumiy_handler(request: Request, exc: Exception):
    # ichki: log qilinadi (bu yerda ko'rsatilmaydi); tashqi: umumiy xabar
    return JSONResponse(status_code=500, content={"xato": "ichki server xatosi", "kod": "SERVER_XATO"})


class Kurs(BaseModel):
    nom: str
    narx: float


@app.post("/kurslar")
def yarat(kurs: Kurs):
    return {"nom": kurs.nom, "narx": kurs.narx}


@app.get("/nosoz")
def nosoz():
    _ = {"a": 1}["yoq_kalit"]     # KeyError — kutilmagan xato
    return {"ok": True}


def main() -> None:
    client = TestClient(app, raise_server_exceptions=False)

    print("=== 1. To'g'ri ma'lumot ===")
    print(f"  → {client.post('/kurslar', json={'nom': 'Python', 'narx': 100}).json()}")

    print("\n=== 2. ⚠️ Validatsiya xatosi (o'zgartirilgan) ===")
    javob = client.post("/kurslar", json={"nom": "X"})
    print(f"  status {javob.status_code} → {javob.json()}")

    print("\n=== 3. ⚠️ Kutilmagan xato (500) ===")
    javob = client.get("/nosoz")
    print(f"  status {javob.status_code} → {javob.json()}")

    print("\n=== 4. Ichki ma'lumot yashiringan ===")
    print(f"  javobda 'KeyError' yoki stack trace bormi: {'KeyError' in javob.text}")
    print("  ⭐ validatsiya → izchil 422; kutilmagan → umumiy 500 (xavfsiz)")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. To'g'ri ma'lumot ===
  → {'nom': 'Python', 'narx': 100.0}

=== 2. ⚠️ Validatsiya xatosi (o'zgartirilgan) ===
  status 422 → {'xato': "kiritilgan ma'lumot noto'g'ri", 'kod': 'VALIDATSIYA', 'maydonlar': 1}

=== 3. ⚠️ Kutilmagan xato (500) ===
  status 500 → {'xato': 'ichki server xatosi', 'kod': 'SERVER_XATO'}

=== 4. Ichki ma'lumot yashiringan ===
  javobda 'KeyError' yoki stack trace bormi: False
  ⭐ validatsiya → izchil 422; kutilmagan → umumiy 500 (xavfsiz)

Nima ko'rsatdi: 2.4, 2.6, 2.7-bo'limlar.

Misol 4 — Amaliy: to'liq xato tizimi

Barcha xato qatlamlarini birlashtirgan API: maxsus domen xatolari, validatsiya, kutilmagan xato — hammasi izchil shaklda. Bu — real API'ning professional xato boshqaruvi.

python
"""to'liq xato tizimi: maxsus xatolar (topilmadi, ruxsat), izchil shakl (xato+kod), validatsiya, 500; barcha qatlam."""

import warnings
warnings.filterwarnings("ignore")

from typing import Annotated

from fastapi import Depends, FastAPI, Header, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient
from pydantic import BaseModel

app = FastAPI(title="Wisar API")

BAZA = {1: {"id": 1, "nom": "Python", "muallif": "ali"}}


class KursTopilmadi(Exception):
    def __init__(self, kurs_id: int):
        self.kurs_id = kurs_id


class RuxsatYoq(Exception):
    pass


def _javob(status_code: int, xato: str, kod: str) -> JSONResponse:
    return JSONResponse(status_code=status_code, content={"xato": xato, "kod": kod})


@app.exception_handler(KursTopilmadi)
def h_topilmadi(request: Request, exc: KursTopilmadi):
    return _javob(404, f"kurs {exc.kurs_id} topilmadi", "KURS_YOQ")


@app.exception_handler(RuxsatYoq)
def h_ruxsat(request: Request, exc: RuxsatYoq):
    return _javob(403, "bu amal uchun ruxsat yo'q", "RUXSAT_YOQ")


@app.exception_handler(RequestValidationError)
def h_validatsiya(request: Request, exc: RequestValidationError):
    return _javob(422, "kiritilgan ma'lumot noto'g'ri", "VALIDATSIYA")


@app.exception_handler(Exception)
def h_umumiy(request: Request, exc: Exception):
    return _javob(500, "ichki server xatosi", "SERVER_XATO")


class KursYangilash(BaseModel):
    nom: str


@app.get("/kurslar/{kurs_id}")
def kurs(kurs_id: int):
    if kurs_id not in BAZA:
        raise KursTopilmadi(kurs_id)
    return BAZA[kurs_id]


@app.put("/kurslar/{kurs_id}")
def yangila(kurs_id: int, kurs: KursYangilash, x_token: Annotated[str | None, Header()] = None):
    if kurs_id not in BAZA:
        raise KursTopilmadi(kurs_id)
    if x_token != "admin-token":
        raise RuxsatYoq()
    BAZA[kurs_id]["nom"] = kurs.nom
    return BAZA[kurs_id]


def main() -> None:
    client = TestClient(app, raise_server_exceptions=False)

    print("=== 1. Muvaffaqiyatli ===")
    print(f"  /kurslar/1 → {client.get('/kurslar/1').json()['nom']}")

    print("\n=== 2. Topilmadi (404, izchil) ===")
    print(f"  /kurslar/999 → {client.get('/kurslar/999').json()}")

    print("\n=== 3. Ruxsat yo'q (403, izchil) ===")
    javob = client.put("/kurslar/1", json={"nom": "X"}, headers={"X-Token": "yolgon"})
    print(f"  → status {javob.status_code}, {javob.json()}")

    print("\n=== 4. Validatsiya (422, izchil) ===")
    javob = client.put("/kurslar/1", json={}, headers={"X-Token": "admin-token"})
    print(f"  → status {javob.status_code}, {javob.json()}")
    print("  ⭐ barcha xato bir shaklda: {'xato': '...', 'kod': '...'}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Muvaffaqiyatli ===
  /kurslar/1 → Python

=== 2. Topilmadi (404, izchil) ===
  /kurslar/999 → {'xato': 'kurs 999 topilmadi', 'kod': 'KURS_YOQ'}

=== 3. Ruxsat yo'q (403, izchil) ===
  → status 403, {'xato': "bu amal uchun ruxsat yo'q", 'kod': 'RUXSAT_YOQ'}

=== 4. Validatsiya (422, izchil) ===
  → status 422, {'xato': "kiritilgan ma'lumot noto'g'ri", 'kod': 'VALIDATSIYA'}
  ⭐ barcha xato bir shaklda: {'xato': '...', 'kod': '...'}

Nima ko'rsatdi: 2.1–2.8-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Har xato turlicha shaklda" Izchil shakl
"Xato endpointda boshqariladi" Global handler (markaz)
"Stack trace javobda" Yashirish (xavfsizlik)
"Domen xatosi = HTTP xato" Maxsus klass ajratadi
"Validatsiya xatosi o'zgarmas" O'zgartirish mumkin
"500 tafsilotli bo'lsin" Umumiy xabar (tashqi)
"Xato kodi keraksiz" Mashina uchun foydali
"Har xato try/except" Handler markazlashtiradi

6. Keng tarqalgan xatolar va yechimlari

1. Nomuvofiq xato shakli

python
return {"error": ...}    # bir joyda
return {"message": ...}  # boshqada        # ⚠️
# ✅ izchil: {"xato": ..., "kod": ...}

2. Stack trace'ni oshkor qilish

python
return JSONResponse(500, {"xato": str(exc)})   # ⚠️ ichki ma'lumot
return JSONResponse(500, {"xato": "ichki xatosi"})   # ✅ umumiy

3. Har endpointda xato boshqaruvi

python
try: ... except KursTopilmadi: return ...      # ⚠️ har joyda
# ✅ @app.exception_handler(KursTopilmadi)

4. Domen xatosi bilan HTTP aralashtirish

python
if not kurs: raise HTTPException(404, ...)     # domen kodida HTTP
# ✅ raise KursTopilmadi(id) — handler HTTP qiladi

5. Request parametrini unutish

python
def handler(exc): ...                          # ❌ request kerak
def handler(request: Request, exc): ...        # ✅

6. JSONResponse o'rniga return dict

python
def handler(request, exc): return {"xato": ...}   # ⚠️ status yo'q
def handler(request, exc): return JSONResponse(status_code=404, content=...)   # ✅

7. Kutilmagan xatoni ushlamaslik

python
# faqat aniq xatolar handler'i               # ⚠️ 500 xom stack trace
@app.exception_handler(Exception)              # ✅ umumiy 500

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 12-qism (o'tilgan): istisnolar — maxsus xato klasslari
  • 20.5-dars (o'tilgan): Pydantic — RequestValidationError
  • 20.6-dars (o'tilgan): HTTPException, status kodlar
  • 20.11-dars (o'tilgan): ruxsat — 403 xatolari
  • 20.16-dars: OpenAPI — xato javoblarini hujjatlash

8. Eng yaxshi amaliyotlar

  1. Barcha xatolar izchil shaklda (xato + kod).

  2. Global exception_handler bilan markazlashtiring.

  3. Maxsus xato klasslari — domen'ni HTTP'dan ajrating.

  4. Ichki ma'lumotni (stack trace, SQL) yashiring.

  5. Kutilmagan xatoni ushlang (Exception → 500 umumiy).

  6. Xato kodi (KURS_YOQ) — mashina uchun (til-mustaqil).

  7. Validatsiya xatosini (422) izchil shaklga soling.

  8. Xatolarni serverda log qiling (foydalanuvchiga umumiy).


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # HTTPException nima uchun?
2.  # exception_handler nima qiladi?
3.  # maxsus xato klassi nega?
4.  # RequestValidationError nima?
5.  # izchil xato shakli nima?
6.  # xato kodi (KURS_YOQ) kim uchun?
7.  # 500 javobda stack trace bo'lsinmi?
8.  # kutilmagan xato status?
9.  # handler'da Request kerakmi?
10. # handler nima qaytaradi?
11. # domen xatosi HTTP xatomi?
12. # stack trace'ni nega yashiramiz?
Javoblar
  1. Aniq (kutilgan) xatolar (status, detail)
  2. Xato turini markazda boshqaradi
  3. Domen mantiqini HTTP'dan ajratadi
  4. Pydantic validatsiya xatosi (422)
  5. Barcha xato bir shaklda (xato + kod)
  6. Mashina (dastur mantiqi, til-mustaqil)
  7. Yo'q (xavfsizlik — yashirish)
  8. 500 (Internal Server Error)
  9. Ha (request: Request, exc)
  10. JSONResponse (status + content)
  11. Yo'q (maxsus klass ajratadi; handler HTTP qiladi)
  12. Xavfsizlik — hujumchiga ma'lumot bermang

Vazifa 2: Xatolarni tuzating

python
1.  return {"error": ...}      # va boshqa joyda {"message": ...}

2.  return JSONResponse(500, {"xato": str(exc)})   # ichki

3.  try: ... except KursTopilmadi: ...   # har endpointda

4.  def handler(exc): ...        # request

5.  def handler(request, exc): return {"xato": ...}   # JSONResponse
Javoblar
python
1.  # izchil: {"xato": ..., "kod": ...}

2.  return JSONResponse(500, {"xato": "ichki server xatosi"})

3.  @app.exception_handler(KursTopilmadi)   # markazda

4.  def handler(request: Request, exc): ...

5.  return JSONResponse(status_code=404, content={"xato": ...})

Vazifa 3: Izchil xato tizimi

Standart xato javob:

  1. Yordamchi funksiya _xato(status, xabar, kod)
  2. Uch maxsus xato (topilmadi, ruxsat, band)
  3. Har biri handler bilan
  4. TestClient bilan izchillikni test

Vazifa 4: Validatsiya boyitish

Validatsiya xatosini yaxshilang:

  1. RequestValidationError handler
  2. Har maydon xatosini (loc, msg) tuzilgan shaklga
  3. O'zbekcha xabarlar
  4. Turli validatsiya xatolarini test

Vazifa 5: Xavfsizlik tekshiruvi

Ichki ma'lumot yashirishni sinang:

  1. Kutilmagan xato (KeyError, ZeroDivisionError)
  2. 500 — umumiy xabar (stack trace yo'q)
  3. Serverda log (foydalanuvchiga umumiy)
  4. Javobda ichki ma'lumot yo'qligini test

Vazifa 6: Xato kodlar katalogi

Xato kodlarini hujjatlang:

  1. Barcha xato kodlari ro'yxati (KURS_YOQ, RUXSAT_YOQ, ...)
  2. Har biri: status, ma'no, sabab
  3. Markazlashgan xato yaratish funksiyasi
  4. To'liq test

Vazifa 7: O'ylash

Maxsus xato klasslari domen mantiqini (KursTopilmadi) HTTP tafsilotidan (404, JSON shakli) ajratadi: endpoint domen tilida gapiradi ("kurs topilmadi"), handler uni HTTP tiliga tarjima qiladi. Bu "muammoni ifodalash" va "muammoni hal qilish" ni ajratish — muhandislik tamoyili. Bu ajratishning afzalligi nima (masalan, HTTP'dan boshqa interfeys — CLI, gRPC — qo'shganda), va u qaysi boshqa joylarda uchraydi?

Javob

Qisqa javob: Maxsus xato klassi domen hodisasini (KursTopilmadi) ifodalaydi, HTTP javobini (404) emas. Endpoint domen tilida gapiradi ("kurs yo'q"), handler HTTP tiliga tarjima qiladi. Afzalligi: domen mantiqi interfeysdan mustaqil — agar keyinchalik HTTP o'rniga CLI, gRPC yoki xabar navbati qo'shsangiz, domen xatosi o'zgarmaydi, faqat yangi "tarjimon" (handler) yozasiz. "Ifodalash vs hal qilish" ajratishi — domen kodni barqaror va qayta ishlatiladigan qiladi.

1. Ifodalash vs hal qilish

Ifodalash (domen) Hal qilish (interfeys)
KursTopilmadi 404 JSON
"Nima bo'ldi" "Qanday javob berish"
Interfeysdan mustaqil HTTP'ga bog'liq

2. Ajratishning afzalligi

Afzallik Sabab
Mustaqillik Domen HTTP'ni bilmaydi
Qayta ishlatish Bir xato, ko'p interfeys
Test Domen alohida sinaladi
O'zgartirish Handler'ni almashtirish

3. Ko'p interfeys misoli

KursTopilmadi (domen xatosi)
    ├── HTTP handler → 404 JSON
    ├── CLI handler → "Xato: kurs yo'q" + exit 1
    └── gRPC handler → NOT_FOUND status

Domen xatosi bir xil, har interfeys o'z tarjimasini beradi.

4. Ajratish boshqa joyda

Domen (ifodalash) Interfeys (hal qilish)
Xato klassi HTTP/CLI/gRPC javob
Biznes mantiq UI/API
Ma'lumot modeli JSON/XML serialization
Hodisa (event) Ishlovchi (handler)

5. Muhandislik saboqlari

  1. Muammoni ifodalash ≠ uni hal qilish
  2. Domen xatosi — interfeysdan mustaqil
  3. Ajratish — qayta ishlatish va mustaqillik
  4. Bir domen, ko'p interfeis (HTTP, CLI, gRPC)

6. Xulosa

  1. Maxsus xato — domen'ni HTTP'dan ajratadi
  2. Endpoint domen tilida, handler HTTP tilida
  3. Ajratish — interfeisdan mustaqillik
  4. Bir xato, ko'p tarjimon (interfeys)

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda xatolarni professional boshqarishni o'rgandik.

Eng muhim uch fikr:

  1. HTTPException va global handler. HTTPException — kutilgan xatolar uchun (topilmadi, ruxsat yo'q); u status kod, detail (satr yoki dict) va qo'shimcha sarlavha beradi. Kattaroq nazorat uchun @app.exception_handler(TurXato) — ma'lum xato turini butun ilovada bir joyda boshqaradi. Bu xato javobini markazlashtiradi — har endpointda try/except yozish shart emas.

  2. Maxsus xato klasslari va izchil shakl. Maxsus xato klassi (KursTopilmadi) domen mantiqini HTTP tafsilotidan ajratadi: endpoint domen xatosini ko'taradi, handler uni HTTP javobga aylantiradi. Barcha xatolar izchil shaklda bo'lsin ({"xato": "...", "kod": "..."}): xato — odam uchun o'qiladigan xabar, kod — mashina uchun (til-mustaqil). Bu mijozga har xatoni bir xil qayta ishlashga imkon beradi.

  3. Xavfsizlik va qatlamlar. Xato javobi ichki ma'lumot (stack trace, SQL xatosi, fayl yo'llari) oshkor qilmasligi kerak — bu hujumchiga yordam beradi. Kutilmagan xatolar (Exception) 500 bilan boshqariladi: foydalanuvchiga umumiy xabar, serverda to'liq log. Xato boshqaruvi qatlam-qatlam: aniq (HTTPException), domen (maxsus), validatsiya (RequestValidationError → 422), va oxirida kutilmagan (500).

Keyingi darsda fayl yuklash ni o'rganamiz: rasm, hujjat va boshqa fayllarni API orqali qabul qilish (UploadFile), tekshirish (turi, hajmi), saqlash va xavfsizlik choralari.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
20.12-dars: Xatolarni boshqarish — IlmHamroh