Express bilan CRUD API yozish
Oldingi yetti darsda marshrut, request, response, middleware va xato
ishlovchisini alohida-alohida ko’rdik. Endi ularni birlashtirib, to’liq
ishlaydigan API yozamiz: vazifalarni qo’shish, ro’yxatini olish,
o’zgartirish va o’chirish.
CRUD nima
Har amal o’z HTTP usuli va manziliga ega. Yozadigan beshta endpoint:
| Usul | Manzil | Vazifa | Muvaffaqiyat kodi |
|---|---|---|---|
GET |
/api/tasks |
Hamma vazifa | 200 |
GET |
/api/tasks/:id |
Bitta vazifa | 200 |
POST |
/api/tasks |
Yangi qo’shish | 201 |
PUT |
/api/tasks/:id |
Yangilash | 200 |
DELETE |
/api/tasks/:id |
O’chirish | 204 |
REST tamoyillari
Yuqoridagi jadval tasodifiy tuzilmagan. U REST uslubiga amal qiladi.
Farqni taqqoslashda ko’rish oson:
| REST uslubida | REST’ga zid |
|---|---|
GET /api/tasks |
GET /api/getAllTasks |
POST /api/tasks |
GET /api/createTask |
DELETE /api/tasks/5 |
GET /api/deleteTask?id=5 |
O’ng ustunda amal manzilga yozilgan va hammasi GET bilan bajarilyapti.
Bu xavfli ham: qidiruv roboti havolani ochsa, ma’lumot o’chib ketishi
mumkin. GET faqat o’qiydi, o’zgartirmaydi. Batafsil
REST, GraphQL va WebSocket darsida.
Ma’lumotni qayerda saqlaymiz
Ma’lumotlar bazasi hali o’tilmagan, shuning uchun vazifalarni oddiy massivda saqlaymiz.
// Vaqtinchalik ombor — server xotirasida
let tasks = [
{ id: 1, title: "Kitob o'qish", isDone: false },
{ id: 2, title: "Kod yozish", isDone: true },
];
let nextId = 3;
let ishlatilgani bejiz emas: DELETE da massivni filter natijasi
bilan almashtiramiz.
Tayyorgarlik
routes/tasks.js faylini ochamiz — marshrutlash darsida
yaratgan Router shu yerda kengayadi.
// routes/tasks.js
const express = require("express");
const router = express.Router();
let tasks = [
{ id: 1, title: "Kitob o'qish", isDone: false },
{ id: 2, title: "Kod yozish", isDone: true },
];
let nextId = 3;
module.exports = router;
app.js esa shunday:
// app.js
const express = require("express");
const tasksRouter = require("./routes/tasks");
const app = express();
// So'rov tanasidagi JSON ni o'qish uchun
app.use(express.json());
app.use("/api/tasks", tasksRouter);
app.use((request, response) => {
response.status(404).json({ error: "Bunday manzil topilmadi" });
});
app.use((err, request, response, next) => {
console.error(err);
response.status(500).json({ error: "Serverda xato yuz berdi" });
});
app.listen(3000, () => {
console.log("Server ishga tushdi: http://localhost:3000");
});
Quyidagi beshta endpoint module.exports qatoridan yuqoriga
yoziladi.
1. GET — hamma vazifa
router.get("/", (request, response) => {
response.json(tasks);
});
curl http://localhost:3000/api/tasks
[{"id":1,"title":"Kitob o'qish","isDone":false},{"id":2,"title":"Kod yozish","isDone":true}]
Eng sodda endpoint: massivni JSON qilib qaytaradi.
2. GET — bitta vazifa
router.get("/:id", (request, response) => {
const id = Number(request.params.id);
const task = tasks.find((item) => item.id === id);
if (!task) {
return response.status(404).json({ error: "Vazifa topilmadi" });
}
response.json(task);
});
curl http://localhost:3000/api/tasks/1
{"id":1,"title":"Kitob o'qish","isDone":false}
Mavjud bo’lmagan raqam:
curl -i http://localhost:3000/api/tasks/99
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
{"error":"Vazifa topilmadi"}
request.params.id matn bo’lgani uchun Number() bilan aylantirildi —
usiz item.id === id taqqoslash hech qachon true bermaydi.
3. POST — yangi vazifa
router.post("/", (request, response) => {
const title = request.body.title;
// Kelgan ma'lumotni ishonchsiz deb qaraymiz
if (!title || title.trim() === "") {
return response.status(400).json({ error: "title maydoni majburiy" });
}
const task = {
id: nextId,
title: title.trim(),
isDone: false,
};
nextId = nextId + 1;
tasks.push(task);
// 201 — yangi resurs yaratildi
response.status(201).json(task);
});
curl -i -X POST http://localhost:3000/api/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Dars tayyorlash"}'
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
{"id":3,"title":"Dars tayyorlash","isDone":false}
Uch jihatga e’tibor bering. id ni server beradi — mijoz yuborgan
id ni qabul qilmaymiz, aks holda ikki vazifa bir xil raqam olishi
mumkin. isDone boshlang’ich qiymati false. Javobda yaratilgan
obyekt qaytariladi — mijoz id ni shu yerdan biladi.
Bo’sh sarlavha bilan sinang:
curl -i -X POST http://localhost:3000/api/tasks \
-H "Content-Type: application/json" \
-d '{"title":" "}'
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
{"error":"title maydoni majburiy"}
4. PUT — yangilash
router.put("/:id", (request, response) => {
const id = Number(request.params.id);
const task = tasks.find((item) => item.id === id);
if (!task) {
return response.status(404).json({ error: "Vazifa topilmadi" });
}
const title = request.body.title;
const isDone = request.body.isDone;
// Faqat yuborilgan maydonlarni yangilaymiz
if (title !== undefined) {
if (title.trim() === "") {
return response.status(400).json({ error: "title bo'sh bo'lmasin" });
}
task.title = title.trim();
}
if (isDone !== undefined) {
task.isDone = Boolean(isDone);
}
response.json(task);
});
curl -X PUT http://localhost:3000/api/tasks/1 \
-H "Content-Type: application/json" \
-d '{"isDone":true}'
{"id":1,"title":"Kitob o'qish","isDone":true}
find massivdagi obyektga havola qaytaradi, shuning uchun
task.isDone = true massivdagi qiymatni ham o’zgartiradi. id esa
o’zgarmaydi — u resursning o’zgarmas belgisi.
5. DELETE — o’chirish
router.delete("/:id", (request, response) => {
const id = Number(request.params.id);
const exists = tasks.some((item) => item.id === id);
if (!exists) {
return response.status(404).json({ error: "Vazifa topilmadi" });
}
tasks = tasks.filter((item) => item.id !== id);
// 204 — muvaffaqiyatli, qaytaradigan ma'lumot yo'q
response.sendStatus(204);
});
curl -i -X DELETE http://localhost:3000/api/tasks/2
HTTP/1.1 204 No Content
filter yangi massiv qaytaradi va uni tasks ga yozamiz — let shuning
uchun kerak edi. 204 javobida tana bo’lmaydi, shuning uchun
response.json() emas, response.sendStatus() ishlatiladi.
To’liq fayl
routes/tasks.js yakuniy ko’rinishi:
const express = require("express");
const router = express.Router();
let tasks = [
{ id: 1, title: "Kitob o'qish", isDone: false },
{ id: 2, title: "Kod yozish", isDone: true },
];
let nextId = 3;
router.get("/", (request, response) => {
response.json(tasks);
});
router.get("/:id", (request, response) => {
const id = Number(request.params.id);
const task = tasks.find((item) => item.id === id);
if (!task) {
return response.status(404).json({ error: "Vazifa topilmadi" });
}
response.json(task);
});
router.post("/", (request, response) => {
const title = request.body.title;
if (!title || title.trim() === "") {
return response.status(400).json({ error: "title maydoni majburiy" });
}
const task = { id: nextId, title: title.trim(), isDone: false };
nextId = nextId + 1;
tasks.push(task);
response.status(201).json(task);
});
router.put("/:id", (request, response) => {
const id = Number(request.params.id);
const task = tasks.find((item) => item.id === id);
if (!task) {
return response.status(404).json({ error: "Vazifa topilmadi" });
}
const title = request.body.title;
const isDone = request.body.isDone;
if (title !== undefined) {
if (title.trim() === "") {
return response.status(400).json({ error: "title bo'sh bo'lmasin" });
}
task.title = title.trim();
}
if (isDone !== undefined) {
task.isDone = Boolean(isDone);
}
response.json(task);
});
router.delete("/:id", (request, response) => {
const id = Number(request.params.id);
const exists = tasks.some((item) => item.id === id);
if (!exists) {
return response.status(404).json({ error: "Vazifa topilmadi" });
}
tasks = tasks.filter((item) => item.id !== id);
response.sendStatus(204);
});
module.exports = router;
To’liq sinov ketma-ketligi
Serverni npm run dev bilan ishga tushiring va quyidagilarni tartib
bilan bajaring:
curl http://localhost:3000/api/tasks
curl -X POST http://localhost:3000/api/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Yangi vazifa"}'
curl -X PUT http://localhost:3000/api/tasks/3 \
-H "Content-Type: application/json" \
-d '{"isDone":true}'
curl -X DELETE http://localhost:3000/api/tasks/3
curl http://localhost:3000/api/tasks
Oxirgi buyruq boshlang’ich ikki vazifani ko’rsatadi: qo’shilgan yozuv yangilandi, so’ng o’chirildi. To’rt amal ham ishladi.
Amaliy mashq
express-app loyihasida davom eting:
routes/tasks.jsdatasksmassivi vanextIdni e’lon qilib,GET /endpointini yozing;GET /:idni qo’shib, mavjud va mavjud bo’lmagan raqam bilan tekshiring;POST /ni yozing va javob kodi201ekaninicurl -ibilan tasdiqlang;- Bo’sh
titleyuborib,400javobini oling; PUT /:idbilan vazifani bajarilgan deb belgilang, so’ngGET /api/tasksda o’zgarish saqlanganini ko’ring;DELETE /:idni yozib, o’chirilgan vazifani qayta so’rang —404chiqishi kerak.
6-qadam butun zanjirni tekshiradi: o’chirish ishlagan bo’lsa, keyingi
so’rov aynan 404 qaytaradi.
Qisqacha xulosa
- CRUD — yaratish, o’qish, yangilash va o’chirish; har biri o’z HTTP usuliga mos keladi.
- REST’da manzil resursni, usul esa amalni bildiradi:
DELETE /api/tasks/5,GET /api/deleteTaskemas. idni server beradi, mijozdan qabul qilinmaydi.- To’g’ri holat kodlari: yaratishda
201, topilmasa404, noto’g’ri ma’lumotda400, o’chirishda204. - Har endpointda kelgan ma’lumot tekshiriladi — bo’sh
titlebazaga tushmasligi kerak. findobyektga havola beradi,filteresa yangi massiv — shuning uchuntasksletbilan e’lon qilinadi.- Xotiradagi massiv server qayta yuklanganda tozalanadi.
Keyingi darsda forma va validatsiya — HTML formadan kelgan ma’lumotni qabul qilish va uni jiddiy tekshirish.