WisarWisar
Dasturlash kitobi/5-QISM — Nodejs18 daqiqa

5.7-bob: REST API dizayni (resurslar, metodlar, status, versiyalash, best practices)

5-QISM — Node.js Backend · 7-mavzu


1. Kirish va motivatsiya

5.5–5.6-boblarda API qanday yozishni (http, Express) o'rgandik. Endi undan ham muhimrog'ini — API'ni qanday dizayn qilishni — o'rganamiz. Ikki dasturchi bir xil funksiyani beradigan API yozishi mumkin, lekin biri toza, bashoratli, kengaytiriladigan, ikkinchisi — chalkash, mo'rt, ishlatib bo'lmaydigan. Farq — dizaynda.

REST (Representational State Transfer) — Roy Fielding (2000) tomonidan ta'riflangan, web API'lar uchun arxitektura uslubi. Bu — qoidalar to'plami emas, balki prinsiplar: resurslarni qanday nomlash, HTTP metodlarini qanday ishlatish, status kodlarni qanday tanlash, javoblarni qanday tuzish. Yaxshi REST API — uni ishlatuvchi (frontend, mobil, boshqa servis) hujjatsiz ham taxmin qila oladigan API.

O'xshatish: REST — yaxshi kutubxona kataloglash tizimi. Har kitob (resurs) mantiqiy joyda (/books/42); kitobni olish (GET), qo'shish (POST), o'chirish (DELETE) — aniq qoidalar. Yangi kutubxonachi (dasturchi) tizimni bir qarashda tushunadi. Yomon API — kitoblar tasodifiy joyda, har biriga boshqacha murojaat — chalkashlik.

Nega muhim?

  • Frontendbackend shartnomasi — API dizayni ikki jamoa kelishuvi (11, 12).
  • Bashoratlilik — yaxshi API'ni ishlatuvchi hujjatsiz taxmin qiladi.
  • Kengaytiriladigan — versiyalash, sahifalash — o'sishga tayyor.
  • Professional belgi — yomon API'ni keyin tuzatish qimmat; yaxshi dizayn boshidan.

2. Nazariya — chuqur tushuntirish

2.1. REST nima va 6 cheklov (constraints)

REST — arxitektura uslubi; 6 prinsip (constraint) ga asoslanadi (Fielding):

  1. Client-Server — frontend va backend ajratilgan 0.4-bob; mustaqil rivojlanadi.
  2. Stateless — har so'rov o'zini-o'zi ta'minlaydi; server so'rovlar orasida holat saqlamaydi (2.7-JS: HTTP stateless).
  3. Cacheable — javoblar keshlanadigan bo'lishi mumkin (0.1, 2.14).
  4. Uniform Interface — bir xil, izchil interfeys (resurs, metod, status) — REST yuragi.
  5. Layered System — qatlamlar (load balancer, cache, API gateway — 9.8) — client bilmaydi.
  6. Code on Demand (ixtiyoriy) — server client'ga kod yuborishi mumkin (kam).

Eng muhim: uniform interface (izchil) + stateless. Bular API'ni bashoratli va masshtablanadigan 9.9-bob qiladi.

2.2. Resource-oriented dizayn (resurs — REST markazi)

REST'da hamma narsa — resurs (ot/narsa): foydalanuvchi, mahsulot, buyurtma. URL — resursni identifikatsiya qiladi; HTTP metod — unga amalni (Microsoft, Stack Overflow):

text
   FE'L (action) URL'da:         OT (resurs) URL'da:
  /getUsers                       GET    /users
  /createUser                     POST   /users
  /deleteUser?id=5                DELETE /users/5
  /updateUserName                 PATCH  /users/5

Asosiy qoida: URL — ot (resurs); HTTP metod — fe'l (amal). /getUsers emas, GET /users. Amal metodda, resursda emas (Stack Overflow).

2.3. Resurs nomlash konvensiyalari

text
   Ko'plik ot:         /users (collection), /users/5 (bitta)
   Iyerarxiya:         /users/5/orders (5-foydalanuvchining buyurtmalari)
   Kichik harf, tire:  /blog-posts (camelCase/underscore emas)
   Versiya:            /api/v1/users (2.10)
   Fe'l:               /getUsers, /createOrder
   Birlik collection:  /user (ko'plik: /users)
   Kengaytma:          /users.json (Accept header — 2.13)

2.4. HTTP metodlar va CRUD (0.4 amaliyoti)

Har CRUD amali — HTTP metod (Microsoft, 0.4):

Metod CRUD Misol Safe? Idempotent?
GET Read GET /users, GET /users/5
POST Create POST /users
PUT Replace (to'liq) PUT /users/5
PATCH Update (qisman) PATCH /users/5 ~
DELETE Delete DELETE /users/5
  • Safe — server holatini o'zgartirmaydi (GET — faqat o'qish; brauzer/proxy keshlaydi — 0.4).
  • Idempotent — bir necha marta chaqirsa ham bir xil natija 2.9-bob.

2.5. PUT vs PATCH (eng ko'p chalkashlik)

text
  PUT /users/5 — TO'LIQ almashtirish (butun obyektni yuborasiz)
    body: { ism: "Ali", email: "a@b.uz", yosh: 20 }   HAMMA maydon
     yo'q maydonlar O'CHADI (yoki default)

  PATCH /users/5 — QISMAN yangilash (faqat o'zgaradigan)
    body: { yosh: 21 }   faqat yosh
     boshqa maydonlar O'ZGARMAYDI

Qaysi: PATCH — kundalik (faqat o'zgargan maydon — kam ma'lumot, xavfsizroq). PUT — to'liq almashtirish kerak bo'lganda. Ko'p API faqat PATCH ishlatadi.

2.6. Status kodlar — to'g'ri tanlash (0.4 chuqur)

To'g'ri status kod — API'ning "tili" (0.4: 2xx/3xx/4xx/5xx):

Kod Qachon
200 OK muvaffaqiyatli GET/PATCH/PUT (ma'lumot bilan)
201 Created POST muvaffaqiyatli (yangi resurs yaratildi)
204 No Content DELETE muvaffaqiyatli (javob body'siz)
400 Bad Request noto'g'ri so'rov (validatsiya — 5.9)
401 Unauthorized autentifikatsiya yo'q/noto'g'ri (5.15)
403 Forbidden autentifikatsiya bor, lekin ruxsat yo'q (RBAC — 5.17)
404 Not Found resurs topilmadi
409 Conflict ziddiyat (masalan email band)
422 Unprocessable Entity validatsiya xatosi (semantik)
429 Too Many Requests rate limit (5.20)
500 Internal Server Error server xatosi (kod buzildi)

401 vs 403: 401 — "kim ekaningni bilmayman" (login kerak — 5.15). 403 — "kim ekaningni bilaman, lekin ruxsating yo'q" (admin emas — 5.17). Bu farqni chalkashtirmang.

2.7. Query parametrlar: filtr, sort, sahifalash (Stack Overflow)

Filtrlash, saralash, sahifalash — query stringda (path'da emas — 2.3):

text
  Filtr:        GET /users?role=admin&active=true
  Saralash:     GET /products?sort=-price (- = kamayish), ?sort=name
  Sahifalash:   GET /posts?page=2&limit=20  (yoki ?offset=20&limit=20)
  Maydon tanlash: GET /users?fields=id,ism  (faqat kerakli maydonlar)
  Qidiruv:      GET /products?search=telefon

2.8. Sahifalash (pagination) — chuqur

Katta to'plamni bo'lak-bo'lak qaytarish (0.1: xotira; 3.1: performance) (Microsoft):

text
  Offset-based:   ?page=2&limit=20 (20–39 yozuvlar) — oddiy, lekin katta offsetda sekin
  Cursor-based:   ?cursor=abc123&limit=20 — tez, real-time uchun (oxirgi ID'dan)

Javobda meta ma'lumot beriladi (jami, sahifa, keyingi bormi):

json
{
  "data": [ ... ],
  "meta": { "page": 2, "limit": 20, "total": 145, "totalPages": 8 }
}

2.9. Idempotency (qayta chaqirish xavfsizligi)

Idempotent — bir necha marta chaqirsa ham bir xil natija (qo'shimcha ta'sirsiz — 2.4). Nega muhim: tarmoq uzilsa 0.4-bob, client qayta urinadi — duplikat yaratilmasligi kerak:

text
  GET /users/5      — 100 marta chaqiring  bir xil (idempotent )
  DELETE /users/5   — 2-marta  allaqachon yo'q (idempotent , 204 yoki 404)
  PUT /users/5      — 2-marta  bir xil holat (idempotent )
  POST /users       — 2-marta  IKKI user! (idempotent EMAS )

POST idempotent emas — qayta yuborilsa duplikat. Yechim: idempotency key (client noyob kalit yuboradi; server takrorni aniqlaydi) — to'lov API'larida muhim.

2.10. Versiyalash (API o'zgarganda)

API o'zgarsa, eski client'lar buzilmasligi uchun versiyalash (Microsoft):

text
  1. URL path (eng keng tarqalgan):  /api/v1/users, /api/v2/users
  2. Header:                         Accept: application/vnd.api.v1+json
  3. Query:                          /users?version=1

URL path versiyalash (/api/v1/) — eng oddiy, ko'rinadigan, ko'p ishlatiladi. Breaking change (4.5: MAJOR — semver 0.7) bo'lsa, /v2 chiqariladi; /v1 qo'llab-quvvatlanadi (eski client buzilmaydi).

2.11. Izchil javob shakli (consistent response)

Barcha javoblar bir xil shaklda bo'lsin — client bashorat qiladi:

json
// Muvaffaqiyat
{ "success": true, "data": { ... } }
// Ro'yxat (meta bilan — 2.8)
{ "success": true, "data": [ ... ], "meta": { ... } }
// Xato (2.12)
{ "success": false, "error": { "code": "NOT_FOUND", "message": "..." } }

Izchillik — frontend (11) uchun katta yengillik: har endpoint javobini res.data.data deb o'qiydi, har xil shaklni o'rganmaydi.

2.12. Xato javoblar formati

Xatolar ham izchil va foydali bo'lsin (5.10 ga ko'prik):

json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Ma'lumot noto'g'ri",
    "details": [
      { "field": "email", "message": "Email noto'g'ri" }
    ]
  }
}

Yomon: 500 + HTML xato sahifasi, yoki har xil shakl. Yaxshi: to'g'ri status 2.6-bob + izchil JSON + tushunarli xabar (texnik tafsilot log'da — 5.12, foydalanuvchiga emas — 14).

2.13. Content negotiation va HTTP semantikasi

  • Content-Type (so'rov) — client nima yuboryapti (application/json).
  • Accept (so'rov) — client nima kutadi (application/json).
  • Content-Type (javob) — server nima qaytaryapti.

REST API odatda JSON 0.4-bob; Content-Type: application/json doim.

2.14. Caching (ETag, Cache-Control)

Cacheable 2.1-bob — javoblarni keshlash (0.1, performance):

text
  Cache-Control: max-age=3600   — 1 soat keshlansin 0.4-bob
  ETag: "abc123"                — resurs versiyasi (o'zgarmagan bo'lsa 304 — 0.4)
  If-None-Match: "abc123"       — client: shu versiyam bor; o'zgardimi?
   304 Not Modified (o'zgarmagan — body yubormaydi, tejaydi)

2.15. HATEOAS (ilg'or — ixtiyoriy)

HATEOAS (Hypermedia as the Engine of Application State) — javobda keyingi mumkin amallar havolalari beriladi:

json
{
  "data": { "id": 5, "ism": "Ali" },
  "links": { "self": "/users/5", "orders": "/users/5/orders" }
}

HATEOAS — "to'liq REST" (Richardson Maturity Model 3-daraja), lekin amalda kam ishlatiladi (murakkab). Ko'p API undan voz kechadi. G'oyani bilish kifoya.

2.16. RESTful bo'lmagan holatlar (amal-asoslangan)

Hamma narsa CRUD'ga to'g'ri kelmaydi. Murakkab amallar uchun fe'l-resurs maqbul:

text
  POST /users/5/activate        — aktivlashtirish (CRUD emas)
  POST /orders/5/cancel         — bekor qilish
  POST /auth/login              — login 5.15-bob
  POST /payments/5/refund       — qaytarish

Pragmatik bo'ling: REST — qoida emas, yo'riqnoma. 95% resurs-asoslangan; murakkab amal uchun fe'l ishlatish — normal.

2.17. API hujjatlash va xavfsizlik (pointerlar)

  • Hujjatlash: Swagger/OpenAPI 5.23-bob — API'ni avtomatik hujjatlaydi.
  • Xavfsizlik: HTTPS (0.4, 14), auth 5.15-bob, rate limit 5.20-bob, CORS 5.20-bob, validatsiya 5.9-bob.
  • Versiyalash + deprecation: eski versiyani ogohlantirib (header), keyin o'chirish.

3. Sintaksis — REST dizayn yo'riqnomasi

text
RESURS:   ot, ko'plik — /users, /users/5, /users/5/orders
METOD:    GET (o'qish), POST (yaratish201), PUT (to'liq), PATCH (qisman), DELETE (204)
STATUS:   200/201/204  | 400/401/403/404/409/422/429 (client) | 500 (server)
QUERY:    ?role=admin (filtr) &sort=-price &page=2&limit=20 (2.7, 2.8)
VERSIYA:  /api/v1/... 2.10-bob
JAVOB:    { success, data, meta } / { success:false, error } (2.11, 2.12)

4. Batafsil kod namunalari (Express bilan — 5.6)

Misol 1 — RESTful resurs route'lari (2.2, 2.4)

js
import { Router } from "express";       // (5.6)
const router = Router();

// Resurs: users (ot, ko'plik — 2.3)
router.get("/", getAllUsers);           // GET    /users — ro'yxat
router.get("/:id", getUser);            // GET    /users/5 — bitta
router.post("/", createUser);           // POST   /users — yaratish (201)
router.patch("/:id", updateUser);       // PATCH  /users/5 — qisman (2.5)
router.delete("/:id", deleteUser);      // DELETE /users/5 — o'chirish (204)

// Iyerarxik resurs (2.3)
router.get("/:id/orders", getUserOrders);   // GET /users/5/orders

export default router;
// app.use("/api/v1/users", router)   versiya bilan (2.10)

Misol 2 — To'g'ri status kodlar (2.6)

js
// GET — 200 yoki 404
const getUser = (req, res) => {
  const user = users.find(u => u.id === Number(req.params.id));   // (5.6)
  if (!user) {
    return res.status(404).json({ success: false, error: { code: "NOT_FOUND", message: "Foydalanuvchi topilmadi" } });   // (2.6, 2.12)
  }
  res.status(200).json({ success: true, data: user });           // (2.11)
};

// POST — 201 Created
const createUser = (req, res) => {
  const yangi = { id: nextId++, ...req.body };
  users.push(yangi);
  res.status(201).json({ success: true, data: yangi });          // 201! (2.6)
};

// DELETE — 204 No Content
const deleteUser = (req, res) => {
  users = users.filter(u => u.id !== Number(req.params.id));
  res.status(204).end();                                          // body'siz (2.6)
};

Misol 3 — Sahifalash (pagination — 2.8)

js
const getAllUsers = (req, res) => {
  const page = Math.max(1, Number(req.query.page) || 1);          // (5.6: query)
  const limit = Math.min(100, Number(req.query.limit) || 20);    // max 100 (DoS — 14)
  const offset = (page - 1) * limit;

  const sahifaData = users.slice(offset, offset + limit);        // (2.7-JS: slice)
  const total = users.length;

  res.json({
    success: true,
    data: sahifaData,
    meta: {                                                       // (2.8)
      page, limit, total,
      totalPages: Math.ceil(total / limit),
      hasNext: offset + limit < total,
    }
  });
};
// GET /users?page=2&limit=20

Misol 4 — Filtr va saralash (2.7)

js
const getProducts = (req, res) => {
  let natija = [...products];                                     // nusxa (2.7-JS)

  // Filtr (2.7)
  const { category, minPrice, inStock } = req.query;
  if (category) natija = natija.filter(p => p.category === category);
  if (minPrice) natija = natija.filter(p => p.price >= Number(minPrice));
  if (inStock === "true") natija = natija.filter(p => p.stock > 0);

  // Saralash 2.7-bob: ?sort=-price (kamayish), ?sort=name (o'sish)
  const sort = req.query.sort;
  if (sort) {
    const desc = sort.startsWith("-");                            // (2.6-JS)
    const maydon = desc ? sort.slice(1) : sort;
    natija.sort((a, b) => desc ? b[maydon] - a[maydon] : a[maydon] - b[maydon]);  // (3.9)
  }

  res.json({ success: true, data: natija });
};
// GET /products?category=phone&minPrice=100&sort=-price

Misol 5 — PUT vs PATCH (2.5)

js
// PUT — TO'LIQ almashtirish (barcha maydon kerak — 2.5)
const replaceUser = (req, res) => {
  const idx = users.findIndex(u => u.id === Number(req.params.id));
  if (idx === -1) return res.status(404).json({ success: false, error: { message: "Topilmadi" } });
  const { ism, email, yosh } = req.body;                         // hamma maydon
  if (!ism || !email) return res.status(400).json({ success: false, error: { message: "Barcha maydon kerak" } });
  users[idx] = { id: users[idx].id, ism, email, yosh };          // TO'LIQ almashtir
  res.json({ success: true, data: users[idx] });
};

// PATCH — QISMAN (faqat berilgan maydonlar — 2.5)
const updateUser = (req, res) => {
  const user = users.find(u => u.id === Number(req.params.id));
  if (!user) return res.status(404).json({ success: false, error: { message: "Topilmadi" } });
  Object.assign(user, req.body);                                 // faqat berilganlar (2.8-JS)
  res.json({ success: true, data: user });
};

Misol 6 — Versiyalash (URL path — 2.10)

js
import express from "express";
import usersV1 from "./routes/v1/users.js";
import usersV2 from "./routes/v2/users.js";

const app = express();
app.use(express.json());                                          // (5.6)

app.use("/api/v1/users", usersV1);     // eski (qo'llab-quvvatlanadi)
app.use("/api/v2/users", usersV2);     // yangi (breaking change — 4.5)
// v1 client'lar buzilmaydi; yangi client'lar v2 (2.10)

Misol 7 — Izchil javob va xato (helper — 2.11, 2.12)

js
// Javob helper'lari (izchillik — 2.11)
const ok = (res, data, status = 200) => res.status(status).json({ success: true, data });
const fail = (res, status, code, message, details) =>
  res.status(status).json({ success: false, error: { code, message, ...(details && { details }) } });

// Ishlatish
const getUser = (req, res) => {
  const user = users.find(u => u.id === Number(req.params.id));
  if (!user) return fail(res, 404, "NOT_FOUND", "Foydalanuvchi topilmadi");   // (2.12)
  ok(res, user);                                                              // (2.11)
};
const createUser = (req, res) => {
  if (!req.body.email) return fail(res, 400, "VALIDATION", "Email kerak");
  const yangi = { id: nextId++, ...req.body };
  users.push(yangi);
  ok(res, yangi, 201);                                                        // 201
};

Misol 8 — Nested resurs va amal-asoslangan (2.3, 2.16)

js
// Iyerarxik: foydalanuvchining buyurtmalari (2.3)
router.get("/users/:userId/orders", (req, res) => {
  const orders = barchaBuyurtmalar.filter(o => o.userId === Number(req.params.userId));
  res.json({ success: true, data: orders });
});

// Amal-asoslangan (CRUD emas — 2.16)
router.post("/orders/:id/cancel", (req, res) => {        // bekor qilish
  const order = topBuyurtma(req.params.id);
  if (order.status === "shipped") {
    return res.status(409).json({ success: false, error: { message: "Yuborilgan buyurtma bekor qilinmaydi" } });  // 409 Conflict (2.6)
  }
  order.status = "cancelled";
  res.json({ success: true, data: order });
});

Misol 9 — Caching (ETag — 2.14)

js
import crypto from "node:crypto";       // (5.3)

const getUser = (req, res) => {
  const user = users.find(u => u.id === Number(req.params.id));
  if (!user) return res.status(404).end();

  const etag = crypto.createHash("md5").update(JSON.stringify(user)).digest("hex");  // (5.3: hash)
  res.set("ETag", etag);                                          // (2.14)

  if (req.headers["if-none-match"] === etag) {                    // o'zgarmagan?
    return res.status(304).end();                                 // 304 — body yo'q (tejaydi — 0.4)
  }
  res.json({ success: true, data: user });
};

Misol 10 — To'liq RESTful controller (best practices birga)

js
// controllers/productController.js (5.6: qatlamli)
const products = [];
let nextId = 1;

// GET /products — filtr + sort + pagination (2.7, 2.8)
export const list = (req, res) => {
  let natija = [...products];
  if (req.query.category) natija = natija.filter(p => p.category === req.query.category);
  if (req.query.sort) {
    const desc = req.query.sort.startsWith("-");
    const m = desc ? req.query.sort.slice(1) : req.query.sort;
    natija.sort((a, b) => (desc ? b[m] - a[m] : a[m] - b[m]));
  }
  const page = Number(req.query.page) || 1, limit = Math.min(100, Number(req.query.limit) || 20);
  const data = natija.slice((page - 1) * limit, page * limit);
  res.json({ success: true, data, meta: { page, limit, total: natija.length } });
};

// GET /products/:id (2.6)
export const getOne = (req, res) => {
  const p = products.find(x => x.id === Number(req.params.id));
  if (!p) return res.status(404).json({ success: false, error: { code: "NOT_FOUND", message: "Topilmadi" } });
  res.json({ success: true, data: p });
};

// POST /products (2.6: 201)
export const create = (req, res) => {
  const { nom, price } = req.body;
  if (!nom || price == null) return res.status(400).json({ success: false, error: { code: "VALIDATION", message: "nom va price kerak" } });
  const yangi = { id: nextId++, nom, price, createdAt: new Date().toISOString() };
  products.push(yangi);
  res.status(201).json({ success: true, data: yangi });
};

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

1) Fe'l URL'da (resurs o'rniga)

text
 POST /createUser, GET /getUserById?id=5
 POST /users, GET /users/5 (metod fe'l, URL ot — 2.2)

2) Noto'g'ri status kod

js
//  hammasi 200 (xato ham 200 bilan)
res.json({ error: "topilmadi" });   // status 200!

//  to'g'ri status (2.6)
res.status(404).json({ success: false, error: {...} });

3) Filtr/sahifalashni path'da

text
 /users/admin/page/2  (path'da filtr)
 /users?role=admin&page=2 (query'da — 2.7)

4) Izchil bo'lmagan javob shakli

js
//  har endpoint har xil shakl (frontend qiynaladi)
res.json(users);  // bir joyda massiv
res.json({ result: user });  // boshqa joyda obyekt

//  izchil (2.11)
res.json({ success: true, data: ... });

5) Versiyasiz API (keyin breaking change)

text
 /api/users (versiyasiz)  o'zgarish eski client'larni buzadi
 /api/v1/users 2.10-bob  v2 chiqarib, v1 saqlanadi

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Frontend "qaysi maydonni o'qiyman?" deb chalkashadi

Sababi: izchil bo'lmagan javob shakli 2.11-bob. Yechimi: har javob { success, data }; helper (Misol 7).

Xato 2 — Xatoda 200 status (frontend xatoni sezmaydi)

Sababi: noto'g'ri status 2.6-bob. Yechimi: to'g'ri 4xx/5xx; res.status(...).

Xato 3 — Katta to'plam sekin/xotira to'ladi

Sababi: sahifalashsiz hamma yozuv (0.1, 2.8). Yechimi: pagination (limit majburiy, max chegara — Misol 3).

Xato 4 — POST qayta yuborilib, duplikat

Sababi: POST idempotent emas 2.9-bob. Yechimi: idempotency key; yoki unique constraint (DB — 6).

Xato 5 — API o'zgarib, mobil ilova buzildi

Sababi: versiyasiz breaking change 2.10-bob. Yechimi: versiyalash; eski versiyani saqlash.

Xato 6 — Maxfiy ma'lumot javobda (parol hash)

Sababi: butun obyektni qaytarish (14). Yechimi: faqat kerakli maydonlar (fields yoki controller'da tanlash — passwordni olib tashlang).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • Express 5.6-bob: REST'ning amaliy bajarilishi.
  • HTTP 0.4-bob: metod, status, header — REST'ning quroli.
  • Validatsiya 5.9-bob: 400/422; xato formati.
  • Error handling 5.10-bob: izchil xato javobi.
  • Auth (5.15, 5.17): 401/403; /auth/login.
  • Swagger 5.23-bob: REST API'ni hujjatlash.
  • Frontend (11, 12): API'ni iste'mol qilish — izchil shakl yengillashtiradi.
  • NestJS (8): REST + dekoratorlar (@Get, @Post).

8. Eng yaxshi amaliyotlar (best practices)

  • URL — ot (resurs, ko'plik); metod — fe'l (GET /users — 2.2, 2.3).
  • To'g'ri status kodlar (201 Create, 204 Delete, 404, 400 — 2.6); 401 vs 403 farqi.
  • Filtr/sort/pagination — query'da 2.7-bob; pagination'da limit chegarasi (DoS — 14).
  • Izchil javob shakli ({ success, data, meta }) + xato ({ error }) — helper bilan (2.11, 2.12).
  • Versiyalash (/api/v1/) — breaking change uchun (2.10, 4.5).
  • PATCH (qisman) — kundalik; PUT — to'liq 2.5-bob.
  • Stateless — har so'rov o'zini ta'minlaydi (token — 5.15); server session'ga bog'lanmaydi 2.1-bob.
  • Maxfiy ma'lumotni qaytarmang (parol hash — 14); faqat kerakli maydonlar.
  • Pragmatik REST — murakkab amalga fe'l-resurs 2.16-bob; HATEOAS shart emas.
  • Hujjatla (Swagger — 5.23); HTTPS + auth + rate limit (14).

9. Amaliy loyiha: "Professional RESTful API Dizayni"

REST prinsiplarini amalda mustahkamlash — to'liq, professional API.

Maqsad

Resurs-asoslangan dizayn, to'g'ri metod/status, sahifalash, filtr, versiyalash va izchil javob/xato formatini birlashtirib, professional REST API qurish.

Talablar (requirements)

  1. Kamida 2 resurs (masalan products, orders) — RESTful route'lar (ot, ko'plik, express.Router — 5.6, 2.2).
  2. To'liq CRUD: GET (ro'yxat + bitta), POST (201), PATCH (qisman), PUT (to'liq), DELETE (204) — to'g'ri status (2.4, 2.6).
  3. Sahifalash: ?page=&limit= + meta (total/totalPages/hasNext); limit max chegara (Misol 3, 2.8).
  4. Filtr + saralash: ?category=&minPrice=&sort=-price (Misol 4, 2.7).
  5. Izchil javob: { success, data, meta } / { success:false, error } — helper bilan (Misol 7, 2.11, 2.12).
  6. Versiyalash: /api/v1/... 2.10-bob.
  7. Iyerarxik resurs: /products/:id/reviews yoki /users/:id/orders (2.3, Misol 8).
  8. Amal-asoslangan endpoint: POST /orders/:id/cancel — 409 holati bilan (2.16, Misol 8).
  9. To'g'ri xato status: 400/404/409; maxfiy ma'lumotni qaytarmang (2.6, 6-xato).
  10. (Bonus) ETag bilan caching (Misol 9, 2.14).

Maslahatlar (hint)

  • URL — ot, metod — fe'l 2.2-bob; express.Router 5.6-bob.
  • Status: POST201, DELETE204, topilmadi404 2.6-bob.
  • Pagination: slice((page-1)*limit, page*limit) + meta (Misol 3).
  • Filtr/sort: query'dan o'qib, filter/sort (3.9, Misol 4).
  • Javob helper: ok(res, data) / fail(res, status, code, msg) (Misol 7).
  • limit ni max chegarala (DoS — 14).

"Tayyor" mezonlari (acceptance criteria)

  • Resurslar ot/ko'plik, RESTful route'lar.
  • To'liq CRUD to'g'ri metod/status bilan (201/204/404/400).
  • Sahifalash meta bilan; limit cheklangan.
  • Filtr va saralash query orqali.
  • Izchil javob/xato shakli (helper).
  • Versiyalash (/api/v1/).
  • Iyerarxik va amal-asoslangan endpoint.
  • Maxfiy ma'lumot qaytarilmaydi; to'g'ri status kodlar.

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda REST API dizaynini professional darajada o'rgandik:

  • REST — arxitektura uslubi (6 cheklov: client-server, stateless, cacheable, uniform interface, layered).
  • Resurs-asoslangan: URL — ot/ko'plik (/users/5); metod — fe'l (GET/POST/PUT/PATCH/DELETE — CRUD).
  • Status kodlar (201/204/400/401/403/404/409/422/429/500); 401 vs 403.
  • Query: filtr/sort/pagination (meta bilan); PUT (to'liq) vs PATCH (qisman).
  • Versiyalash (/api/v1/); idempotency (POST emas); izchil javob/xato shakli.
  • Caching (ETag/Cache-Control); pragmatik REST (amal-asoslangan — 2.16).

Keyingi bob — 5.8-bob: Environment variables — dotenv, config. API yozishni va dizaynni bildik; endi uni sozlashni — maxfiy ma'lumot (DB parol, API kalit, port) ni koddan ajratib, environment variables (.env — 4.5) va config tizimini o'rganamiz. Bu — xavfsizlik (14) va turli muhitlar (dev/prod — 10) uchun zarur.


Foydalanilgan rasmiy/ishonchli manbalar

  • Microsoft Azure Architecture — Web API Design Best Practices
  • Stack Overflow Blog — Best practices for REST API design
  • Postman Blog — REST API Best Practices; MDN — HTTP (0.4)

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
5.7-bob: REST API dizayni (resurslar, metodlar, status, versiyalash, best practices) — Wisar