HTTP PUT, PATCH, DELETE — update va o'chirish
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 bilan200 OK); topilmasa —404 - Idempotent: ikki marta yuborilsa ham natija bir xil
[!INFO] Body ichida ham
Idbo'lsa va u URL dagiidbilan mos kelmasa —400 Bad Request. Lekin oddiyroq yo'l — yangilash DTO sidaIdumuman 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 daJsonPatchDocument<T>(Microsoft.AspNetCore.JsonPatchpaketi). 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 uchun204qaytaradi — loyiha bo'ylab bir xil tanlang) - Bog'liq ma'lumot bor (buyurtmalarda ishlatilgan mahsulot) —
409 Conflictyoki 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]