Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. HTTPException chuqurroq
- 2.2. Global xato ishlovchisi
- 2.3. Maxsus xato klasslari
- 2.4. Validatsiya xatosini o'zgartirish
- 2.5. Izchil xato javob shakli
- 2.6. 500 va kutilmagan xatolar
- 2.7. Xavfsizlik (ichki ma'lumotni yashirish)
- 2.8. Xato boshqaruvi qatlamlari
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — HTTPException va tuzilgan detail
- Misol 2 — Maxsus xato klassi va handler
- Misol 3 — Validatsiya va kutilmagan xato
- Misol 4 — Amaliy: to'liq xato tizimi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
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:
-
HTTPExceptionchuqurroq (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
TestClientbilan sinaladi.
2. Nazariya — chuqur tushuntirish
2.1. HTTPException chuqurroq
HTTPException — status kod, xabar va sarlavha (20.6 dan):
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:
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):
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:
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:
{
"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:
@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
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
TestClientbilan sinaladi.
Misol 1 — HTTPException va tuzilgan detail
"""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:
=== 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 sarlavhaNima ko'rsatdi: 2.1-bo'lim.
Misol 2 — Maxsus xato klassi va handler
"""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:
=== 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 ajratadiNima ko'rsatdi: 2.2, 2.3, 2.5-bo'limlar.
Misol 3 — Validatsiya va kutilmagan xato
"""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:
=== 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.
"""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:
=== 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
return {"error": ...} # bir joyda
return {"message": ...} # boshqada # ⚠️
# ✅ izchil: {"xato": ..., "kod": ...}2. Stack trace'ni oshkor qilish
return JSONResponse(500, {"xato": str(exc)}) # ⚠️ ichki ma'lumot
return JSONResponse(500, {"xato": "ichki xatosi"}) # ✅ umumiy3. Har endpointda xato boshqaruvi
try: ... except KursTopilmadi: return ... # ⚠️ har joyda
# ✅ @app.exception_handler(KursTopilmadi)4. Domen xatosi bilan HTTP aralashtirish
if not kurs: raise HTTPException(404, ...) # domen kodida HTTP
# ✅ raise KursTopilmadi(id) — handler HTTP qiladi5. Request parametrini unutish
def handler(exc): ... # ❌ request kerak
def handler(request: Request, exc): ... # ✅6. JSONResponse o'rniga return dict
def handler(request, exc): return {"xato": ...} # ⚠️ status yo'q
def handler(request, exc): return JSONResponse(status_code=404, content=...) # ✅7. Kutilmagan xatoni ushlamaslik
# faqat aniq xatolar handler'i # ⚠️ 500 xom stack trace
@app.exception_handler(Exception) # ✅ umumiy 5007. 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 —
403xatolari - 20.16-dars: OpenAPI — xato javoblarini hujjatlash
8. Eng yaxshi amaliyotlar
Barcha xatolar izchil shaklda (
xato+kod).Global
exception_handlerbilan markazlashtiring.Maxsus xato klasslari — domen'ni HTTP'dan ajrating.
Ichki ma'lumotni (stack trace, SQL) yashiring.
Kutilmagan xatoni ushlang (
Exception→ 500 umumiy).Xato kodi (
KURS_YOQ) — mashina uchun (til-mustaqil).Validatsiya xatosini (
422) izchil shaklga soling.Xatolarni serverda log qiling (foydalanuvchiga umumiy).
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
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
- Aniq (kutilgan) xatolar (status, detail)
- Xato turini markazda boshqaradi
- Domen mantiqini HTTP'dan ajratadi
- Pydantic validatsiya xatosi (422)
- Barcha xato bir shaklda (
xato+kod) - Mashina (dastur mantiqi, til-mustaqil)
- Yo'q (xavfsizlik — yashirish)
- 500 (Internal Server Error)
- Ha (
request: Request, exc) JSONResponse(status + content)- Yo'q (maxsus klass ajratadi; handler HTTP qiladi)
- Xavfsizlik — hujumchiga ma'lumot bermang
Vazifa 2: Xatolarni tuzating
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": ...} # JSONResponseJavoblar
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:
- Yordamchi funksiya
_xato(status, xabar, kod) - Uch maxsus xato (topilmadi, ruxsat, band)
- Har biri handler bilan
TestClientbilan izchillikni test
Vazifa 4: Validatsiya boyitish
Validatsiya xatosini yaxshilang:
RequestValidationErrorhandler- Har maydon xatosini (
loc,msg) tuzilgan shaklga - O'zbekcha xabarlar
- Turli validatsiya xatolarini test
Vazifa 5: Xavfsizlik tekshiruvi
Ichki ma'lumot yashirishni sinang:
- Kutilmagan xato (
KeyError,ZeroDivisionError) 500— umumiy xabar (stack trace yo'q)- Serverda log (foydalanuvchiga umumiy)
- Javobda ichki ma'lumot yo'qligini test
Vazifa 6: Xato kodlar katalogi
Xato kodlarini hujjatlang:
- Barcha xato kodlari ro'yxati (
KURS_YOQ,RUXSAT_YOQ, ...) - Har biri: status, ma'no, sabab
- Markazlashgan xato yaratish funksiyasi
- 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 statusDomen 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
- Muammoni ifodalash ≠ uni hal qilish
- Domen xatosi — interfeysdan mustaqil
- Ajratish — qayta ishlatish va mustaqillik
- Bir domen, ko'p interfeis (HTTP, CLI, gRPC)
6. Xulosa
- Maxsus xato — domen'ni HTTP'dan ajratadi
- Endpoint domen tilida, handler HTTP tilida
- Ajratish — interfeisdan mustaqillik
- 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:
HTTPExceptionva global handler.HTTPException— kutilgan xatolar uchun (topilmadi, ruxsat yo'q); u status kod,detail(satr yokidict) 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 endpointdatry/exceptyozish shart emas.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.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)500bilan 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.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!