Ачааллж байна...
Бид одоо хүртэл нэг зүйлийг байнга хийж ирсэн: функцээс Python объект буцаахад хэрэглэгч JSON хүлээж авдаг. Энэ нь ажилладаг, бид түүнд дассан. Гэхдээ бид түүнийг тайлбарлаагүй.
Энэ хичээл бүхэлдээ тэр хувиргалтад зориулагдана. Юуг хувиргаж болох, юуг болохгүй, хувиргалт яг хэрхэн болдог, хаана хязгаар нь байдаг. Мөн бид нэг чухал зөвлөмжийг ярина: JSON-ы түлхүүрүүдийг ямар үсгээр бичих ёстой вэ.
Энэ бол таны API-ийн гарц — хэрэглэгчид юу очиж байгаа нь энэ. Гарцаа сайн ойлгосон хүн итгэлтэй код бичдэг.
Курс 2-ын Бүлэг 6-д та JSON-ыг гүнзгий сурсан. Богино сануулга: JSON бол өгөгдөл солилцох нийтлэг текст формат. Python, JavaScript, Java, Go — бүх хэл түүнийг уншиж, бичиж чаддаг. Тиймээс API-ууд түүгээр ярьдаг.
JSON-д хэдхэн төрөл байдаг:
текст ("Сайн байна уу")
тоо (42, 3.14)
үнэн/худал (true, false)
хоосон утга (null)
жагсаалт ([1, 2, 3])
объект ({"key": "value"})
Энэ бол бүх зүйл. JSON-д Python-ы tuple, set, datetime, class байдаггүй. Энэ хязгаарлалт нь чухал бөгөөд бид доор түүн рүү буцаж очно.
Гал тогоонд хоол Python объект хэлбэрээр байдаг — dictionary, list, тоо. Гэхдээ зочин Python-оор ярьдаггүй. Зочин JSON-оор ярьдаг.
Тиймээс хоолыг гаргахын өмнө таваг руу шилжүүлэх ёстой. FastAPI бол тэр ажлыг хийдэг зөөгч: гал тогооны хэлээр байсан зүйлийг зочны хэлээр болгож хувиргадаг.
Гэхдээ зарим зүйл таваг руу шилжихгүй. Хэрэв тогооч хоолоо гал тогооны шкафтай хамт өгөх гэвэл зөөгч зогсох болно — "энийг гаргаж чадахгүй". Яг тэр зүйл Python объектуудтай ч тохиолддог: зарим нь JSON болж чаддаггүй. Тэр тохиолдолд FastAPI алдаа өгнө. Бид түүнийг доор харна.
Хамгийн түгээмэл хэлбэр. main.py файлаа дараах кодоор солино:
python
# main.py
from fastapi import FastAPI
app = FastAPI(title="Номын API")
@app.get("/book")
def get_book():
return {"id": 1, "title": "Цог хийморь", "year": 1962}Хүсэлт:
http://127.0.0.1:8000/bookХариу:
json
{"id":1,"title":"Цог хийморь","year":1962}Python dictionary нь JSON объект болсон. Гадна нь буржгар хаалт, дотор нь түлхүүр-утгын хосууд. Бараг ижилхэн харагдана, учир нь JSON-ы синтакс Python-ы dictionary-гээс санаа авсан.
Гэхдээ ижилхэн биш. Python-д та ганц хашилт ('title') ашиглаж болно; JSON-д зөвхөн давхар хашилт ("title") зөвшөөрөгддөг. FastAPI үүнийг тань засаж өгсөн.
python
# main.py (нэмэлт)
@app.get("/titles")
def get_titles():
return ["Цог хийморь", "Цагаан хэрэм", "Хөх судар"]Хүсэлт:
http://127.0.0.1:8000/titlesХариу:
json
["Цог хийморь","Цагаан хэрэм","Хөх судар"]Python list нь JSON array болсон. Дөрвөлжин хаалт хоёуланд нь адилхан.
Энэ бол бодит API-д хамгийн түгээмэл хэлбэр — жагсаалт буцаах endpoint бараг үргэлж ийм харагддаг:
python
# main.py (нэмэлт)
@app.get("/books")
def get_books():
return [
{"id": 1, "title": "Цог хийморь", "year": 1962},
{"id": 2, "title": "Цагаан хэрэм", "year": 1971},
]Хүсэлт:
http://127.0.0.1:8000/booksХариу:
json
[{"id":1,"title":"Цог хийморь","year":1962},{"id":2,"title":"Цагаан хэрэм","year":1971}]Гаднаа array, дотор нь объектууд. Курс 2-ын Бүлэг 5-д та энэ бүтцийг сурахдаа "энэ бол яг JSON-ы авдаг хэлбэр" гэж хэлж байсан. Одоо та түүнийг өөрөө үйлдвэрлэж байна.
Гүн бүтэц ч ажиллана:
python
# main.py (нэмэлт)
@app.get("/library")
def get_library():
return {
"name": "Улаанбаатарын номын сан",
"is_open": True,
"founded": 1921,
"rating": 4.5,
"closed_message": None,
"books": [
{"id": 1, "title": "Цог хийморь", "tags": ["роман", "сонгодог"]},
{"id": 2, "title": "Цагаан хэрэм", "tags": ["роман"]},
],
"address": {
"city": "Улаанбаатар",
"district": "Сүхбаатар",
},
}Хүсэлт:
http://127.0.0.1:8000/libraryХариу:
json
{"name":"Улаанбаатарын номын сан","is_open":true,"founded":1921,"rating":4.5,"closed_message":null,"books":[{"id":1,"title":"Цог хийморь","tags":["роман","сонгодог"]},{"id":2,"title":"Цагаан хэрэм","tags":["роман"]}],"address":{"city":"Улаанбаатар","district":"Сүхбаатар"}}Энэ хариуг сайтар шинжилье, учир нь энд бүх төрлийн хувиргалт нэг дор харагдаж байна.
Текст ("Улаанбаатарын номын сан") хашилттай хэвээр үлдсэн.
Python-ы True нь JSON-ы true болсон — жижиг үсгээр. Энэ бол хэлний ялгаа: Python том үсгээр эхэлдэг, JSON жижиг үсгээр.
Бүхэл тоо (1921) хашилтгүй үлдсэн.
Бутархай тоо (4.5) ч хашилтгүй үлдсэн. JSON бүхэл болон бутархай тоог ялгадаггүй — хоёулаа зүгээр л "тоо".
Python-ы None нь JSON-ы null болсон.
books талбар нь дотроо объектуудын жагсаалт агуулж байна, тэдгээрийн дотор дахин жагсаалт (tags) байна. Гүн ямар ч байсан ажиллана.
address талбар нь объект дотор объект. Мөн ажиллана.
Гурван түвшний гүнтэй бүтцийг та ганц return мөрөөр өгсөн. FastAPI бүхэлд нь дүрсэлж, JSON болгосон.
Функц заавал dictionary эсвэл list буцаах албагүй:
python
# main.py (нэмэлт)
@app.get("/count")
def get_count():
return 42
@app.get("/name")
def get_name():
return "Номын API"
@app.get("/is-open")
def get_is_open():
return True
@app.get("/nothing")
def get_nothing():
return NoneХариунууд:
http://127.0.0.1:8000/count -> 42
http://127.0.0.1:8000/name -> "Номын API"
http://127.0.0.1:8000/is-open -> true
http://127.0.0.1:8000/nothing -> nullБүгд хүчинтэй JSON. Анзаараарай: /name хариу нь хашилттай ("Номын API"), учир нь JSON-д текст заавал хашилттай байдаг.
Гэхдээ практикт ингэж хийхийг зөвлөдөггүй. Ганц утга буцаах endpoint нь ирээдүйд өргөжих боломжгүй. Өнөөдөр 42 буцаадаг endpoint маргааш "нийт тоо ба сүүлийн шинэчлэлтийн огноо" буцаах шаардлагатай болвол та хариуны бүтцийг бүхэлд нь өөрчлөх ёстой болно — тэгвэл таны API-г ашиглаж байгаа бүх программ эвдэрнэ.
Тиймээс дүрэм: үргэлж dictionary (эсвэл dictionary-үүдийн list) буцаа.
python
@app.get("/count")
def get_count():
return {"total": 42}Одоо ирээдүйд {"total": 42, "updated_at": "2026-07-14"} гэж өргөжүүлэхэд хуучин хэрэглэгчид эвдрэхгүй — тэд total талбараа хэвээр олно. Энэ бол API зохион бүтээхэд суралцах эхний зөвлөгөө юм.
Энэ бол чухал бөгөөд нэг удаа шийдэх ёстой асуулт. Бүлэг 1-д бид ийм код бичсэн:
python
return {"мэссэж": "Сайн байна уу"}Энэ ажилласан. Кирилл түлхүүр техникийн хувьд хүчинтэй JSON юм.
Гэхдээ бид түүнийг цаашид хийхгүй, тодорхой шалтгаантай.
JSON-ы түлхүүр бол програмчлалын нэр, хүний уншдаг текст биш. Таны API-г ашиглах программ ийм код бичих болно:
python
response = requests.get("http://.../books/1")
data = response.json()
print(data["title"])Тэр data["title"] гэсэн хэсэг бол таны сонгосон түлхүүр. Хэрэв та "гарчиг" гэж нэрлэсэн бол тэд data["гарчиг"] гэж бичих ёстой болно — кирилл үсгээр, гар солиод, алдаа гарах эрсдэлтэй. Хэрэв таны API-г гадаадын программ, эсвэл гар утасны апп, эсвэл вэб хуудас ашиглавал энэ нь бүр ч төвөгтэй болно.
Түүнчлэн олон хэрэгсэл (JavaScript, database, тохиргооны файл) латин үсэгтэй нэрийг илүү сайн зохицуулдаг.
Тиймээс дүрэм:
Түлхүүр (key) — латин үсгээр, англиар: title, year, is_active.
Утга (value) — ямар ч хэлээр: "Цог хийморь", "Улаанбаатар".
python
return {
"title": "Цог хийморь", # түлхүүр латин, утга кирилл
"city": "Улаанбаатар",
"message": "Ном амжилттай нэмэгдлээ",
}Энэ бол Курс 1-ээс хойш баримталж ирсэн зарчмын үргэлжлэл: техникийн нэр англиар, тайлбар монголоор. Хувьсагчийн нэр, функцийн нэр англиар байдаг шиг JSON-ы түлхүүр ч англиар байна. Хэрэглэгчид харагдах текст нь монголоор байна.
Энэ хичээлээс хойш бид энэ дүрмийг чанд баримтална.
Одоо хязгаарыг харъя. Дараах endpoint-ийг нэмнэ:
python
# main.py (нэмэлт)
@app.get("/broken")
def get_broken():
return {"tags": {"роман", "сонгодог"}}Анзаараарай: {"роман", "сонгодог"} — энэ бол set, list биш. Курс 2-ын Бүлэг 5-д та set-тэй танилцсан: давхардалгүй цуглуулга, дөрвөлжин биш буржгар хаалттай.
Хүсэлт:
http://127.0.0.1:8000/brokenТерминал дээр (улаан traceback):
ValueError: [TypeError("'set' object is not iterable"), TypeError('vars() argument must have __dict__ attribute')]Browser дээр (статус 500):
json
{"detail":"Internal Server Error"}Юу болов? JSON-д set гэж байдаггүй. JSON-д зөвхөн array (жагсаалт) байдаг. FastAPI set-ийг ямар JSON төрөл болгохоо мэдэхгүй тул зогссон.
Мессежийг бүрэн ойлгох шаардлагагүй — гол нь set гэдэг үг тэнд байгаа. Асуудал энэ.
Засвар
python
@app.get("/broken")
def get_broken():
return {"tags": list({"роман", "сонгодог"})}list() ашиглан set-ийг list болгож хувиргалаа.
Хариу:
json
{"tags":["сонгодог","роман"]}(Дараалал өөр байж болно — set нь дараалал хадгалдаггүй.)
Ижил төрлийн бусад асуудал
Python-ы tuple нь ажилладаг — FastAPI түүнийг array болгоно. Гэхдээ JSON-д tuple гэсэн ойлголт байхгүй тул хэрэглэгч array хүлээж авна, tuple биш.
Python-ы datetime объект ч ажилладаг — FastAPI түүнийг ISO форматын текст болгоно ("2026-07-14T10:30:00"). Энэ бол FastAPI-ийн нэмэлт тусламж; энгийн json.dumps() үүнийг хийж чадахгүй.
Гэхдээ таны өөрийн бичсэн энгийн class нь ажиллахгүй:
python
class Book:
def __init__(self, title):
self.title = title
@app.get("/bad")
def get_bad():
return Book("Цог хийморь")Энэ нь 500 өгнө. FastAPI таны class-ыг хэрхэн JSON болгохоо мэдэхгүй.
Гэхдээ энэ асуудлыг Бүлэг 4-т бид бүрмөсөн шийднэ. Тэнд бид Pydantic model сурах бөгөөд тэр нь яг үүнд зориулагдсан: class бичээд, FastAPI түүнийг автоматаар JSON болгоно. Одоохондоо dictionary ашиглаж байгаа нь түр зуурын шийдэл юм.
Нэг зүйлийг тодорхой болгоё. Таны функц Python объект буцаадаг. Хэрэглэгч JSON текст хүлээж авдаг. Хооронд нь FastAPI jsonable_encoder гэдэг зүйл ажилладаг.
Дараалал нь ийм:
Таны функц Python объект буцаана.
FastAPI түүнийг JSON-той нийцтэй энгийн Python объект болгож хувиргана (datetime -> текст, tuple -> list, гэх мэт).
Дараа нь түүнийг жинхэнэ JSON текст болгож хувиргана.
Тэр текстийг сүлжээгээр илгээнэ.
Хэрэглэгч зөвхөн текст хүлээж авдаг. Курс 2-ын Бүлэг 11-д та response.json() гэж дуудаж, тэр текстийг Python объект болгож буцаан хувиргаж байсан.
Тиймээс гинж бүхэлдээ ийм: таны Python объект -> JSON текст -> сүлжээ -> JSON текст -> хэрэглэгчийн Python объект. Хоёр талдаа хувиргалт болдог. Дунд нь зөвхөн текст явдаг.
Set буцаах
Дээр үзсэн. TypeError: 'set' object is not iterable гэх мэт мессеж терминал дээр гарна. Засвар: list() ашиглана.
Өөрийн class буцаах
Дээр дурдсан. 500 гарна. Засвар: dictionary болгож хувиргах, эсвэл Бүлэг 4-ийг хүлээх.
Хариу хоосон харагдах
python
@app.get("/books")
def get_books():
books = [{"id": 1, "title": "Цог хийморь"}]
# return мартсанХариу:
json
nullАлдаа гарахгүй, гэхдээ null ирнэ. Учир нь Python-д return байхгүй функц None буцаадаг, None нь JSON-д null болдог.
Энэ алдааг олоход хэцүү байдаг, учир нь ямар ч анхааруулга гардаггүй. null харвал эхлээд return мөрөө шалгаарай.
Хэвлэсэн зүйл хариунд орохгүй
python
@app.get("/books")
def get_books():
print({"id": 1, "title": "Цог хийморь"})print() бол буцаах биш, терминал дээр харуулах. Хэрэглэгч дахиад null хүлээж авна.
Курс 1-ээс хойш давтагдсан ялгаа: print бол харуулах, return бол өгөх. Сервер дээр энэ ялгаа улам чухал болно, учир нь print нь зөвхөн танд, терминал дээр харагдана; хэрэглэгч түүнийг хэзээ ч харахгүй.
Хүсвэл datetime буцааж үзээрэй:
python
from datetime import datetime
@app.get("/now")
def get_now():
return {"current_time": datetime.now()}Хариуг ажиглаарай — FastAPI огноог автоматаар текст болгосон байх болно. Энэ нь энгийн json.dumps() хийж чадахгүй зүйл юм.
Сонирхвол өөрийн гүн үүрлэсэн бүтэц зохиож үзээрэй — objects дотор list, тэдгээрийн дотор дахин objects. Хэр гүн явж болохыг хараарай. Практик хязгаар байхгүй.
FastAPI Python объектыг автоматаар JSON болгодог: dict -> объект, list -> array, True -> true, None -> null.
Үүрлэсэн бүтэц (объект дотор жагсаалт дотор объект) ямар ч гүнд ажиллана.
Ганц утга (тоо, текст) буцааж болох ч зөвлөдөггүй — үргэлж dictionary буцаа, ирээдүйд өргөжих боломжтой байхын тулд.
JSON-ы түлхүүр латин үсгээр (англиар), утга нь монголоор. Энэ дүрмийг цаашид чанд баримтална.
Python-ы set болон өөрийн бичсэн class JSON болж чаддаггүй — 500 өгнө. Set-ийг list() болгоно; class-ыг Бүлэг 4-т Pydantic шийднэ.
return мартвал null ирнэ, ямар ч анхааруулгагүй. print нь хариу биш.
Одоо та хариуны агуулгыг удирдаж чадна. Гэхдээ HTTP хариу нь зөвхөн агуулгаас бүрддэггүй — түүнд бас status code гэсэн тоо байдаг. Одоохондоо таны бүх хариу 200 буцааж байна, тэр ч байтугай "Ном олдсонгүй" гэсэн хариу ч 200 буцааж байна. Энэ бол худал: та "бүх зүйл сайн" гэж хэлээд алдаа өгч байна.
Дараагийн хичээлд бид status code-ыг серверийн талаас удирдаж сурна. Курс 2-т та тэдгээрийг хэрэглэгчийн талаас уншиж байсан; одоо та тэднийг өөрөө сонгож эхэлнэ.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.