HTTP GET va POST — [HttpGet], [HttpPost], IActionResult
Muammodan boshlaylik
Mahsulotlar API si uchun ikki asosiy amal:
- Mahsulotlar ro'yxatini va bitta mahsulotni olish
- Yangi mahsulot yaratish
Qaysi HTTP metodini ishlatish, javobda qanday status qaytarish, yaratilgan ob'ektni qanday qaytarish? Va action qaytish turi qanday bo'lishi kerak — Mahsulot, IActionResult yoki ActionResult<Mahsulot>?
HTTP metodlari
| Metod | Vazifa | Body | Xavfsiz (o'zgartirmaydi) | Idempotent |
|---|---|---|---|---|
GET |
Olish | Yo'q | ✅ | ✅ |
POST |
Yaratish | Bor | ❌ | ❌ |
PUT |
To'liq almashtirish | Bor | ❌ | ✅ |
PATCH |
Qisman o'zgartirish | Bor | ❌ | ❌ |
DELETE |
O'chirish | Odatda yo'q | ❌ | ✅ |
Idempotent — bir xil so'rovni bir necha marta yuborish natijasi bir marta yuborish bilan bir xil. POST ikki marta — ikkita mahsulot; PUT ikki marta — bir xil holat. PUT, PATCH, DELETE — 43-dars.
Hayotiy o'xshatma
Kutubxona. GET — katalogdan kitobni qidirib ko'rish: necha marta qarasangiz ham kutubxona o'zgarmaydi. POST — yangi kitobni fondga topshirish: ikki marta topshirsangiz — ikki nusxa paydo bo'ladi.
GET — olish
[ApiController]
[Route("api/[controller]")]
public class MahsulotlarController(IMahsulotService service) : ControllerBase
{
// GET api/mahsulotlar?kategoriya=telefon&sahifa=1
[HttpGet]
public async Task<ActionResult<List<MahsulotDto>>> Royxat(
[FromQuery] string? kategoriya,
[FromQuery] int sahifa = 1,
CancellationToken ct = default)
{
var natija = await service.RoyxatAsync(kategoriya, sahifa, ct);
return Ok(natija);
}
// GET api/mahsulotlar/5
[HttpGet("{id:int}")]
public async Task<ActionResult<MahsulotDto>> Ol(int id, CancellationToken ct)
{
var m = await service.OlAsync(id, ct);
if (m is null) return NotFound();
return m; // ActionResult<T> — avtomatik Ok(m)
}
}
- Ro'yxat —
200(bo'sh bo'lsa ham[]va200,404emas) - Bitta element topilmasa —
404
POST — yaratish
public record MahsulotYaratDto(string Nomi, decimal Narx, int Qoldiq, int KategoriyaId);
[HttpPost]
public async Task<ActionResult<MahsulotDto>> Yarat([FromBody] MahsulotYaratDto dto, CancellationToken ct)
{
var yangi = await service.YaratAsync(dto, ct);
return CreatedAtAction(nameof(Ol), new { id = yangi.Id }, yangi);
}
So'rov:
POST /api/mahsulotlar
Content-Type: application/json
{ "nomi": "Choynak", "narx": 120000, "qoldiq": 10, "kategoriyaId": 2 }
Javob:
HTTP/1.1 201 Created
Location: http://localhost:5123/api/mahsulotlar/42
Content-Type: application/json
{ "id": 42, "nomi": "Choynak", "narx": 120000, "qoldiq": 10 }
201 Created— yaratildi (200emas)Locationsarlavhasi — yangi resursning manzili;CreatedAtActionuniOlaction i vaiddan avtomatik yasaydi- Body da — yaratilgan ob'ekt (server bergan
Idbilan) - JSON →
MahsulotYaratDto— avtomatik (model binding);[ApiController]da[FromBody]taxmin qilinadi
[!WARNING] POST uchun alohida kiruvchi DTO (
MahsulotYaratDto) ishlating — entity yoki to'liq modelni emas. Aks holda mijozId,YaratilganSana,Tasdiqlangankabi maydonlarni ham yuborib, o'zi o'rnatishi mumkin (over-posting). DTO — 45-dars.
Qaytish turlari
1. Aniq tur
[HttpGet]
public List<MahsulotDto> Royxat() => service.Royxat(); // doim 200
Faqat bitta natija bo'lsa; NotFound() qaytarib bo'lmaydi.
2. IActionResult
[HttpGet("{id}")]
public IActionResult Ol(int id)
{
var m = service.Ol(id);
return m is null ? NotFound() : Ok(m);
}
Har qanday status qaytarish mumkin, lekin javob turi kodda ko'rinmaydi — Swagger uni bilmaydi.
3. ActionResult<T> — tavsiya etiladi
[HttpGet("{id}")]
public ActionResult<MahsulotDto> Ol(int id)
{
var m = service.Ol(id);
if (m is null) return NotFound();
return m; // T dan avtomatik 200
}
| Aniq tur | IActionResult |
ActionResult<T> |
|
|---|---|---|---|
| Har xil status kodlar | ❌ | ✅ | ✅ |
| Javob turi ko'rinadi (Swagger) | ✅ | ❌ (atribut kerak) | ✅ |
return obj; qisqa yozuv |
✅ | ❌ | ✅ |
[!TIP] Swagger uchun mumkin bo'lgan barcha javoblarni ko'rsating:
[ProducesResponseType(StatusCodes.Status201Created)],[ProducesResponseType(StatusCodes.Status400BadRequest)]. Klient dasturchilari va avtomatik generatsiya qilinadigan klient kodi aniq bo'ladi (72-dars).
Async
Baza yoki tarmoq bilan ishlasa — async Task<ActionResult<T>> va CancellationToken (30-dars).
Bir nechta route — bitta action
[HttpGet("{id:int}")]
[HttpGet("kod/{kod}")] // ikkalasi ham shu action ga
public ActionResult<MahsulotDto> Ol(int? id, string? kod) { ... }
Kam ishlatiladi — odatda alohida action yaxshiroq.
Tez-tez uchraydigan xatolar
POST dan 200 qaytarish — 201 Created + Location.
Body bo'sh keladi:
Content-Type: application/json sarlavhasi yo'q yoki JSON maydon nomlari mos emas → DTO null/standart qiymatlar bilan. [ApiController] da noto'g'ri JSON → avtomatik 400.
GET da body yuborish — GET body si standart bo'yicha ma'nosiz; filtrlar — query string.
Bo'sh ro'yxat uchun 404 — ro'yxat endpoint i bo'sh natijada 200 va [].
Xulosa
HTTP metodlari: GET — olish (xavfsiz, idempotent), POST — yaratish (idempotent emas). GET ro'yxat — 200 va [] ham; bitta topilmasa — 404. POST — 201 Created + Location (CreatedAtAction) + yaratilgan ob'ekt.
Kiruvchi ma'lumot — alohida DTO, over-posting dan himoya. Qaytish turi — ActionResult<T>: har xil status va Swagger uchun aniq tur. Async action lar + CancellationToken; [ProducesResponseType] — hujjat uchun.
Keyingi dars
43-dars: HTTP PUT, PATCH, DELETE — update va o'chirish