11-bo‘lim
API loyihalash
REST prinsiplari, resurs nomlari, HTTP kodlari, xatolarni qaytarish, versiyalash va OpenAPI hujjati.
Ushbu bo‘lim mundarijasi
API - tizimingizning tashqi dunyo bilan shartnomasi. Uni o'zgartirish qiyin, shuning uchun boshidanoq to'g'ri loyihalash muhim.
REST asoslari #
REST - resurslarga asoslangan yondashuv: har bir narsa resurs, unga HTTP metodlari qo'llanadi.
GET /api/mahsulotlar/42/ochirish ← XATO
Nima uchun xavfli:
- Brauzer va proksi
GETso'rovlarini keshlaydi - Qidiruv robotlari havolalarni avtomatik ochadi
- Foydalanuvchi sahifani yangilasa - amal takrorlanadi
Ma'lum bir loyihada qidiruv roboti barcha "o'chirish" havolalarini bosib chiqqan va butun katalogni o'chirgan.
Resurs nomlari #
| Qoida | Yomon | Yaxshi |
|---|---|---|
| Ot ishlating, fe'l emas | /getMahsulot | /mahsulotlar |
| Ko'plik shakli | /mahsulot/42 | /mahsulotlar/42 |
| Kichik harflar | /Mahsulotlar | /mahsulotlar |
| Chiziqcha, pastki chiziq emas | /buyurtma_elementlari | /buyurtma-elementlari |
| Ierarxiya | /buyurtmaElementlari?id=5 | /buyurtmalar/5/elementlar |
Oxirida / yo'q | /mahsulotlar/ | /mahsulotlar |
GET /api/v1/mahsulotlar ro'yxat
POST /api/v1/mahsulotlar yaratish
GET /api/v1/mahsulotlar/42 bitta
PUT /api/v1/mahsulotlar/42 to'liq yangilash
PATCH /api/v1/mahsulotlar/42 qisman yangilash
DELETE /api/v1/mahsulotlar/42 o'chirish
GET /api/v1/mahsulotlar/42/sharhlar ichki resurs
POST /api/v1/mahsulotlar/42/sharhlar sharh qo'shish
GET /api/v1/buyurtmalar/17/elementlar
Amallar uchun #
Ba'zi amallar CRUD ga to'g'ri kelmaydi:
POST /api/v1/buyurtmalar/17/bekor-qilish
POST /api/v1/mahsulotlar/42/nashr-qilish
POST /api/v1/foydalanuvchilar/8/parolni-tiklash
POST /api/v1/sessiyalar (kirish)
DELETE /api/v1/sessiyalar/joriy (chiqish)
POST /api/v1/buyurtmalar/17/bekor-qilish - "bekor qilish so'rovini
yaratish" degan ma'noda.
Bu sof REST emas, lekin amaliy va tushunarli.
HTTP holat kodlari #
HTTP/1.1 200 OK
{"success": false, "error": "Mahsulot topilmadi"}
Bu noto'g'ri. HTTP allaqachon xato bildirish mexanizmiga ega:
HTTP/1.1 404 Not Found
{"xato": {"kod": "mahsulot_topilmadi", "xabar": "Mahsulot topilmadi"}}
Nima uchun muhim: monitoring vositalari, proksi va mijoz kutubxonalari holat kodiga qarab ishlaydi.
- 401 Unauthorized - "kim ekaningizni bilmayman" (kirish kerak)
- 403 Forbidden - "kim ekaningizni bilaman, lekin ruxsat yo'q"
Nomlar chalkash: 401 aslida "autentifikatsiya kerak" degani.
So'rov va javob formati #
POST /api/v1/buyurtmalar
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
{
"elementlar": [
{"mahsulot_id": 42, "soni": 2},
{"mahsulot_id": 17, "soni": 1}
],
"manzil_id": 5,
"tolov_usuli": "karta",
"izoh": "Kechqurun yetkazing"
}
HTTP/1.1 201 Created
Location: /api/v1/buyurtmalar/1042
Content-Type: application/json
{
"malumot": {
"id": 1042,
"raqam": "B-20260815-0042",
"holat": "yangi",
"jami": {"qiymat": 750000, "valyuta": "UZS"},
"yaratilgan": "2026-08-15T14:22:31+05:00",
"elementlar": [
{
"mahsulot_id": 42,
"nomi": "Klaviatura Logitech",
"narx": {"qiymat": 250000, "valyuta": "UZS"},
"soni": 2,
"summa": {"qiymat": 500000, "valyuta": "UZS"}
}
]
}
}
malumot ichiga o'rang{"malumot": {...}}
Nima uchun? Keyinchalik meta ma'lumot qo'shish oson bo'ladi:
{
"malumot": [...],
"meta": {"jami": 245, "sahifa": 3},
"havolalar": {"keyingi": "/api/v1/mahsulotlar?sahifa=4"}
}
Massivni to'g'ridan-to'g'ri qaytarsangiz, meta qo'shish uchun buzuvchi o'zgarish kerak bo'ladi.
Xatolarni qaytarish #
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"xato": {
"kod": "validatsiya_xatosi",
"xabar": "So'rovda xatolar bor",
"tafsilotlar": [
{
"maydon": "elementlar.0.soni",
"kod": "min_qiymat",
"xabar": "Soni kamida 1 bo'lishi kerak"
},
{
"maydon": "manzil_id",
"kod": "topilmadi",
"xabar": "Bunday manzil mavjud emas"
}
],
"sorov_id": "req_8f3a1d0e4b7c"
}
}
| Maydon | Nima uchun |
|---|---|
kod | Dastur uni tekshirishi uchun (matn o'zgarishi mumkin) |
xabar | Odam o'qishi uchun |
tafsilotlar | Qaysi maydonda muammo |
sorov_id | Qo'llab-quvvatlashga murojaat qilganda |
sorov_id ni jurnalga ham yozing - foydalanuvchi shu raqamni
aytsa, muammoni bir zumda topasiz.
{
"xato": "SQLSTATE[23000]: Integrity constraint violation:
1062 Duplicate entry '[email protected]' for key 'uq_email'
in /var/www/app/Repozitoriy.php:142"
}
Bu hujumchiga baza tuzilmasi, fayl yo'llari va texnologiyani oshkor qiladi.
Foydalanuvchiga: "Bu email allaqachon ro'yxatdan o'tgan".
Jurnalga: to'liq tafsilot.
Sahifalash #
GET /api/v1/mahsulotlar?sahifa=3&chegara=20
{
"malumot": [...],
"meta": {
"jami": 245,
"sahifa": 3,
"chegara": 20,
"sahifalar": 13
},
"havolalar": {
"ozi": "/api/v1/mahsulotlar?sahifa=3&chegara=20",
"birinchi": "/api/v1/mahsulotlar?sahifa=1&chegara=20",
"oldingi": "/api/v1/mahsulotlar?sahifa=2&chegara=20",
"keyingi": "/api/v1/mahsulotlar?sahifa=4&chegara=20",
"oxirgi": "/api/v1/mahsulotlar?sahifa=13&chegara=20"
}
}
OFFSET 100000 juda sekin - baza 100 000 qatorni o'qib tashlab yuboradi.
GET /api/v1/hodisalar?kursor=eyJpZCI6MTA0Mn0&chegara=50
SELECT * FROM hodisalar WHERE id > 1042 ORDER BY id LIMIT 50;
Bu har doim tez ishlaydi va yangi yozuv qo'shilganda takrorlanish bo'lmaydi.
Filtrlash, saralash, tanlash #
GET /api/v1/mahsulotlar
?kategoriya=5
&narx_dan=100000
&narx_gacha=500000
&mavjud=true
&qidiruv=klaviatura
&saralash=-narx,nomi
&maydonlar=id,nomi,narx
final class MahsulotFiltri
{
public function __construct(
public readonly ?int $kategoriyaId = null,
public readonly ?int $narxDan = null,
public readonly ?int $narxGacha = null,
public readonly ?bool $mavjud = null,
public readonly ?string $qidiruv = null,
public readonly array $saralash = ['id' => 'asc'],
) {}
public static function sorovdan(array $parametrlar): self
{
return new self(
kategoriyaId: isset($parametrlar['kategoriya'])
? (int) $parametrlar['kategoriya'] : null,
narxDan: isset($parametrlar['narx_dan'])
? (int) $parametrlar['narx_dan'] : null,
qidiruv: $parametrlar['qidiruv'] ?? null,
saralash: self::saralashniTahlilQiling($parametrlar['saralash'] ?? 'id'),
);
}
private static function saralashniTahlilQiling(string $satr): array
{
$ruxsat = ['id', 'nomi', 'narx', 'yaratilgan'];
$natija = [];
foreach (explode(',', $satr) as $maydon) {
$yonalish = str_starts_with($maydon, '-') ? 'desc' : 'asc';
$maydon = ltrim($maydon, '-+');
if (in_array($maydon, $ruxsat, true)) {
$natija[$maydon] = $yonalish;
}
}
return $natija ?: ['id' => 'asc'];
}
}
// SQL inyeksiya
$sql = "SELECT * FROM mahsulotlar ORDER BY {$_GET['saralash']}";
Ustun nomlarini parametrlash mumkin emas - faqat oq ro'yxat.
Autentifikatsiya #
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
| Usul | Qachon |
|---|---|
| API kalit | Server-server, oddiy holat |
| JWT | Stateless, mikroservislar |
| OAuth 2.0 | Uchinchi tomon ilovalari |
| Sessiya cookie | Bir domendagi veb-ilova |
JWT server tomonda saqlanmaydi - shuning uchun uni muddatidan oldin bekor qilish mumkin emas.
Foydalanuvchi chiqsa yoki bloklansa, token muddati tugaguncha amal qiladi.
Yechimlar:
- Qisqa muddat (15 daqiqa) + yangilash tokeni
- Qora ro'yxat (lekin bu stateless afzalligini yo'qotadi)
Chegaralash #
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1755264000
Retry-After: 3600
{
"xato": {
"kod": "chegara_oshdi",
"xabar": "Soatiga 1000 so'rov chegarasi oshdi. 1 soatdan keyin urinib ko'ring."
}
}
X-RateLimit-Remaining mijozga qancha so'rov qolganini aytadi -
u chegaraga yetmasdan o'zini sekinlashtira oladi.
Versiyalash #
| Buzuvchi | Buzuvchi emas |
|---|---|
| Maydonni o'chirish | Yangi maydon qo'shish |
| Maydon nomini o'zgartirish | Yangi ixtiyoriy parametr |
| Maydon turini o'zgartirish | Yangi endpoint |
| Yangi majburiy parametr | Yangi holat kodi (hujjatlashtirilgan) |
| Xato formatini o'zgartirish | Ishlash yaxshilanishi |
Postel qonuni: *"Yuborayotganingizda qat'iy, qabul qilayotganingizda bag'rikeng bo'ling."*
Idempotentlik #
POST /api/v1/buyurtmalar
Idempotency-Key: 8f3a1d0e-4b7c-4a5f-9d1e-3b6c8a0f2d4e
final class IdempotentlikOraliqQatlami
{
public function ishlang(Sorov $sorov, callable $keyingi): Javob
{
$kalit = $sorov->sarlavha('Idempotency-Key');
if ($kalit === null) {
return $keyingi($sorov);
}
$saqlangan = $this->kesh->oling("idem:{$kalit}");
if ($saqlangan !== null) {
return $saqlangan;
}
$javob = $keyingi($sorov);
if ($javob->kod() < 500) {
$this->kesh->saqlang("idem:{$kalit}", $javob, 86400);
}
return $javob;
}
}
Mijoz "Buyurtma berish" tugmasini bosdi, tarmoq uzildi, javob kelmadi. U yana bosdi.
Idempotentlik kaliti bo'lmasa - ikkita buyurtma yaratiladi.
To'lov API lari uchun bu majburiy talab.
OpenAPI hujjati #
openapi: 3.0.3
info:
title: Onlayn do'kon API
version: 1.0.0
description: Mahsulotlar va buyurtmalar bilan ishlash
servers:
- url: https://api.dokon.uz/v1
description: Ishlab chiqarish
- url: https://sinov-api.dokon.uz/v1
description: Sinov muhiti
paths:
/mahsulotlar:
get:
summary: Mahsulotlar ro'yxati
parameters:
- name: kategoriya
in: query
schema: { type: integer }
- name: sahifa
in: query
schema: { type: integer, default: 1, minimum: 1 }
responses:
'200':
description: Muvaffaqiyatli
content:
application/json:
schema:
type: object
properties:
malumot:
type: array
items:
$ref: '#/components/schemas/Mahsulot'
post:
summary: Yangi mahsulot yaratish
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MahsulotSorovi'
responses:
'201':
description: Yaratildi
'422':
description: Validatsiya xatosi
components:
schemas:
Mahsulot:
type: object
required: [id, nomi, narx]
properties:
id: { type: integer, example: 42 }
nomi: { type: string, example: "Klaviatura Logitech" }
narx:
type: object
properties:
qiymat: { type: integer, example: 250000 }
valyuta: { type: string, example: "UZS" }
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
- Interaktiv hujjat (Swagger UI) - sinab ko'rish mumkin
- Mijoz kutubxonasi avtomatik yaratiladi (o'nlab tilda)
- So'rov validatsiyasi sxema asosida
- Soxta server frontend jamoasi uchun
- Avtomatik testlar sxemaga muvofiqlikni tekshiradi
npx @redocly/cli preview-docs openapi.yaml
npx @openapitools/openapi-generator-cli generate -i openapi.yaml -g php
REST ga muqobil #
| Uslub | Qachon |
|---|---|
| REST | Umumiy holat, ochiq API |
| GraphQL | Mijoz kerakli maydonlarni o'zi tanlaydi |
| gRPC | Xizmatlararo, yuqori ishlash |
| WebSocket | Real vaqt, ikki tomonlama |
| Webhook | Server mijozga xabar beradi |
// Webhook yuborish
final class WebhookYuboruvchi
{
public function yuboring(string $url, array $hodisa, string $sir): void
{
$tana = json_encode($hodisa, JSON_UNESCAPED_UNICODE);
$imzo = hash_hmac('sha256', $tana, $sir);
$this->http->post($url, [
'sarlavhalar' => [
'Content-Type' => 'application/json',
'X-Webhook-Imzo' => $imzo,
'X-Webhook-Hodisa' => $hodisa['turi'],
],
'tana' => $tana,
]);
}
}
Qabul qiluvchi xabar haqiqatan sizdan kelganini tekshira olishi kerak. Aks holda har kim soxta webhook yuborishi mumkin.
API loyihalash tekshiruv ro'yxati #
| Talab | Bajarildi |
|---|---|
| Resurs nomlari ot va ko'plikda | |
| HTTP metodlari to'g'ri ishlatilgan | |
| Holat kodlari mos | |
| Xato formati bir xil | |
| Sahifalash amalga oshirilgan | |
| Filtrlash oq ro'yxat bilan | |
| Autentifikatsiya va huquq tekshiruvi | |
| Chegaralash yoqilgan | |
| Versiya URL da | |
| OpenAPI hujjati yozilgan | |
| CORS to'g'ri sozlangan | |
| Barcha so'rovlar jurnalga yoziladi | |
| Ichki tafsilotlar oshkor qilinmaydi |
- Blog uchun REST API endpointlarini loyihalang (postlar, izohlar, teglar).
- Har biri uchun HTTP metod va holat kodini yozing.
- Xato javob formatini belgilang va uchta misol yozing.
- Sahifalash bilan javob namunasini yozing.
- Filtr va saralash parametrlarini loyihalang.
- Saralash uchun oq ro'yxat tekshiruvini yozing.
Idempotency-Keyoraliq qatlamini yozing.- OpenAPI faylini yozing (kamida 4 ta endpoint).
- Swagger UI da ochib ko'ring.
- Buzuvchi va buzuvchi bo'lmagan o'zgarishlarga 5 tadan misol yozing.
Xulosa #
- REST - resurslarga asoslangan yondashuv; metod ma'nosini o'zgartirmang.
- GET hech nima o'zgartirmasin - u keshlanadi va avtomatik ochiladi.
- Resurs nomlari - ot, ko'plikda, kichik harflarda.
- To'g'ri holat kodini qaytaring, har doim 200 emas.
- 401 - kirish kerak, 403 - huquq yo'q.
- Javobni
malumotichiga o'rang - kelajakda meta qo'shish uchun. - Xatoda kod, xabar va so'rov identifikatori bo'lsin.
- Ichki tafsilotlarni hech qachon oshkor qilmang.
- Katta ma'lumotda kursor sahifalash ishlating.
- Idempotentlik kaliti takroriy amallardan himoya qiladi.
- OpenAPI hujjatdan tashqari kod va testlar ham beradi.
Keyingi bo'limda testlash asoslarini o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.