HTTP PUT, PATCH, DELETE — update va o'chirish

~15 daq · .NET Backend · Web API — Controller va Routing

Muammodan boshlaylik

Mahsulotlarni ko'rish va yaratish tayyor (42-dars). Endi admin:

  • Mahsulotni tahrirlaydi — barcha maydonlarini
  • Faqat narxini o'zgartiradi — boshqa maydonlarni yubormasdan
  • Mahsulotni o'chiradi

Hammasini POST /api/mahsulotlar/tahrirlash, POST /api/mahsulotlar/ochirish qilib yozish mumkin — lekin bu REST an'analariga zid, va klientlar API ni taxmin qila olmaydi.


Hayotiy o'xshatma

Kutubxona kartochkasi. PUT — eski kartochkani tashlab, to'liq yangisini yozish: unutilgan maydon bo'sh qoladi. PATCH — kartochkadagi bitta qatorni o'chirg'ich bilan tuzatish. DELETE — kartochkani katalogdan olib tashlash.


PUT — to'liq yangilash

public record MahsulotYangilaDto(string Nomi, decimal Narx, int Qoldiq, int KategoriyaId);

// PUT api/mahsulotlar/5
[HttpPut("{id:int}")]
public async Task<IActionResult> Yangila(int id, MahsulotYangilaDto dto, CancellationToken ct)
{
    var topildi = await service.YangilaAsync(id, dto, ct);
    return topildi ? NoContent() : NotFound();
}
PUT /api/mahsulotlar/5
Content-Type: application/json

{ "nomi": "Choynak (yangi)", "narx": 135000, "qoldiq": 8, "kategoriyaId": 2 }
  • ID — URL dan, ma'lumot — body dan
  • Resurs to'liq almashtiriladi — body da barcha maydonlar bo'lishi kerak
  • Javob: 204 No Content (yoki yangilangan ob'ekt bilan 200 OK); topilmasa — 404
  • Idempotent: ikki marta yuborilsa ham natija bir xil

[!INFO] Body ichida ham Id bo'lsa va u URL dagi id bilan mos kelmasa — 400 Bad Request. Lekin oddiyroq yo'l — yangilash DTO sida Id umuman bo'lmasligi: ID faqat URL dan.


PATCH — qisman yangilash

Faqat narxni o'zgartirish uchun to'liq ob'ektni yuborish — ortiqcha, va bir vaqtda boshqa maydonni o'zgartirgan boshqa foydalanuvchining o'zgarishini "ustidan yozib" yuboradi.

Oddiy usul — maxsus DTO

public record NarxOzgartirDto(decimal Narx);

// PATCH api/mahsulotlar/5/narx
[HttpPatch("{id:int}/narx")]
public async Task<IActionResult> NarxOzgartir(int id, NarxOzgartirDto dto, CancellationToken ct)
{
    var topildi = await service.NarxOzgartirAsync(id, dto.Narx, ct);
    return topildi ? NoContent() : NotFound();
}

Umumiy usul — nullable maydonlar

public record MahsulotPatchDto(string? Nomi, decimal? Narx, int? Qoldiq);

[HttpPatch("{id:int}")]
public async Task<IActionResult> Patch(int id, MahsulotPatchDto dto, CancellationToken ct)
{
    var m = await db.Mahsulotlar.FindAsync([id], ct);
    if (m is null) return NotFound();

    if (dto.Nomi is not null) m.Nomi = dto.Nomi;
    if (dto.Narx is not null) m.Narx = dto.Narx.Value;
    if (dto.Qoldiq is not null) m.Qoldiq = dto.Qoldiq.Value;

    await db.SaveChangesAsync(ct);
    return NoContent();
}

Kelmagan maydon — null — o'zgarmaydi. Cheklovi: maydonni ataylab null ga o'zgartirib bo'lmaydi.

[!TIP] Standartlashgan usul — JSON Patch (RFC 6902): [{ "op": "replace", "path": "/narx", "value": 135000 }], ASP.NET Core da JsonPatchDocument<T> (Microsoft.AspNetCore.JsonPatch paketi). Kuchli, lekin murakkabroq; ko'p loyihalar uchun aniq maqsadli endpoint lar (/narx, /holat) sodda va tushunarli.

Amal sifatidagi o'zgarishlar

Holat o'zgarishi — oddiy maydon yangilash emas, biznes amal:

[HttpPost("{id:int}/bekor-qilish")]     // PATCH holat = "bekor" emas
public async Task<IActionResult> BekorQil(int id, CancellationToken ct) { ... }

Buyurtmani bekor qilish — to'lovni qaytarish, omborni tiklash, xabar yuborish. Bu — alohida endpoint.


DELETE — o'chirish

// DELETE api/mahsulotlar/5
[HttpDelete("{id:int}")]
[Authorize(Roles = "admin")]
public async Task<IActionResult> Ochir(int id, CancellationToken ct)
{
    var topildi = await service.OchirAsync(id, ct);
    return topildi ? NoContent() : NotFound();
}
  • Javob: 204 No Content
  • Allaqachon o'chirilgan — 404 (ba'zi API lar idempotentlik uchun 204 qaytaradi — loyiha bo'ylab bir xil tanlang)
  • Bog'liq ma'lumot bor (buyurtmalarda ishlatilgan mahsulot) — 409 Conflict yoki soft delete

Soft delete

public class Mahsulot
{
    // ...
    public bool Ochirilgan { get; set; }
    public DateTime? OchirilganVaqt { get; set; }
}

Haqiqiy o'chirish o'rniga belgilash — tarix saqlanadi, eski buyurtmalar buzilmaydi, xato bilan o'chirilganini tiklash mumkin. EF Core da global filtr bilan ro'yxatlardan avtomatik yashiriladi.


To'liq CRUD — umumiy ko'rinish

Amal Metod va URL Muvaffaqiyat Xatolar
Ro'yxat GET /api/mahsulotlar 200 —
Bitta GET /api/mahsulotlar/5 200 404
Yaratish POST /api/mahsulotlar 201 + Location 400, 409
To'liq yangilash PUT /api/mahsulotlar/5 204 / 200 400, 404
Qisman PATCH /api/mahsulotlar/5 204 / 200 400, 404
O'chirish DELETE /api/mahsulotlar/5 204 404, 409

[!WARNING] O'zgartiruvchi endpoint lar (POST, PUT, PATCH, DELETE) — har doim avtorizatsiya bilan (61-dars) va resurs egasini tekshirib: PUT /api/buyurtmalar/42 — 42-buyurtma aynan shu foydalanuvchinikimi? ID ni almashtirib, boshqa foydalanuvchining ma'lumotini o'zgartirish (IDOR) — eng ko'p uchraydigan API zaifliklaridan biri.


Tez-tez uchraydigan xatolar

PUT da maydonlarni yubormaslik — ular standart qiymat (0, null) bilan saqlanadi.

O'chirish uchun GET:

[HttpGet("{id}/ochir")]     // ❌ brauzer oldindan yuklasa yoki bot kirsa — o'chadi

Faqat ID bo'yicha yangilash — egasini tekshirmaslik.


Xulosa

PUT — resursni to'liq almashtirish, idempotent, 204/200, topilmasa 404; ID — URL dan. PATCH — qisman: aniq maqsadli endpoint (/narx), nullable DTO yoki JSON Patch. Biznes amallar (bekor qilish, tasdiqlash) — alohida POST endpoint lar.

DELETE — 204; bog'liqlik bo'lsa 409 yoki soft delete. O'zgartiruvchi barcha endpoint lar — avtorizatsiya va egasini tekshirish bilan; o'chirish hech qachon GET orqali emas.


Keyingi dars

44-dars: Route parametrlari — {id}, [FromRoute], [FromQuery], [FromBody]