Express yakuniy loyiha: to'liq ilova

O’n ikki dars oldin task-app ilovasidagi vazifalar oddiy massivda yotardi va server o’chganda yo’qolardi. Hozir sizda baza, model qatlami, migratsiya tizimi, kirish tizimi, fayl yuklash, xavfsizlik qatlamlari va testlar bor.

Bu dars yangi tushuncha o’rgatmaydi. U o’tilganni bir joyga yig’adi va sizga tekshirib ko’radigan to’liq loyiha beradi.

Bo’limni jamlash

Har qatordagi havola — o’sha tushuncha batafsil yozilgan dars.

Tushuncha Asosiy vosita Dars
Doimiy saqlash node:sqlite, prepare Bazani ulash
Kod tuzilishi models/, routes/ Model qatlami
Sxemani boshqarish migrations/, migrate.js Migratsiya va seed
Serverning xotirasi express-session, cookie Sessiya va cookie
Hisob yaratish bcrypt.hash Ro’yxatdan o’tish
Kirish va himoya bcrypt.compare, requireAuth Kirish va himoya
Tokenli API jsonwebtoken, Bearer JWT va API token
Fayl qabul qilish multer, multipart/form-data Fayl yuklash
Hujumlardan himoya helmet, CSRF, rate limit Web xavfsizligi
Avtomatik sinash node:test, supertest API testlash
Serverga chiqarish NODE_ENV, PM2, Nginx Deploy

Loyiha nima qiladi

Shaxsiy vazifalar ilovasi. Har foydalanuvchi ro’yxatdan o’tadi, tizimga kiradi va faqat o’z vazifalarini ko’radi. Profil rasmini yuklaydi. API esa mobil ilova uchun token bilan ham ishlaydi.

Oldingi yakuniy loyihadan farqi shu jumlada: “faqat o’z vazifalarini”. O’sha ilovada ma’lumot hamma uchun umumiy edi va server o’chganda yo’qolardi.

Loyiha tuzilishi

task-app/
├── db/
│   └── index.js              ← ulanish
├── migrations/
│   ├── 001-create-tasks.js
│   ├── 002-add-priority.js
│   ├── 003-create-users.js
│   ├── 004-add-task-user.js
│   └── 005-add-user-avatar.js
├── models/
│   ├── task.js
│   └── user.js
├── middleware/
│   ├── auth.js               ← requireAuth
│   └── csrf.js
├── routes/
│   ├── tasks.js              ← HTML sahifalar
│   ├── auth.js               ← kirish, chiqish
│   └── api.js                ← JSON + JWT
├── views/
├── public/
├── uploads/
├── test/
│   ├── tasks.test.js
│   └── auth.test.js
├── app.js                    ← ilova
├── server.js                 ← listen
├── migrate.js
├── seed.js
├── .env
├── .env.example
└── .gitignore

Har papka bitta vazifaga javob beradi. Bu tuzilish model qatlami darsida qo’yilgan qoidaning o’sishi: routes/ ichida SELECT yo’q, models/ ichida response yo’q.

Qadamlar ketma-ketligi

Loyihani noldan yig’sangiz, shu tartibda boring. Har qadam oldingisiga tayanadi.

1-qadam: asos. npm init, express@4, ejs o’rnatish. app.js va server.js ni ajratib yozish — testlash darsida ko’rilganidek.

2-qadam: baza va migratsiyalar. db/index.js, migrate.js va beshta migratsiya fayli. npm run migrate bilan tekshiring.

3-qadam: model qatlami. models/task.js va models/user.js. Serverni ishga tushirmasdan node -e bilan sinang.

4-qadam: kirish tizimi. Sessiya, bcrypt, routes/auth.js, requireAuth.

5-qadam: vazifalar foydalanuvchiga bog’lanadi. Model funksiyalari userId qabul qiladigan bo’ladi.

6-qadam: fayl yuklash. multer, uploads/, avatar marshruti.

7-qadam: xavfsizlik. helmet, CSRF tokeni, rate limiting, .env.

8-qadam: testlar. Kamida oltita test: CRUD, validatsiya, himoya.

9-qadam: deploy tayyorligi. PORT, trust proxy, /health, .gitignore.

Egalik tekshiruvi — eng muhim qism

Beshinchi qadamda eng ko’p xato qilinadi. Model so’roviga user_id sharti har funksiyaga qo’shiladi:

// models/task.js
function getAllByUser(userId) {
  const rows = database
    .prepare("SELECT * FROM tasks WHERE user_id = ? ORDER BY id")
    .all(userId);

  return rows.map(toTask);
}

function getByIdForUser(id, userId) {
  const row = database
    .prepare("SELECT * FROM tasks WHERE id = ? AND user_id = ?")
    .get(id, userId);

  return row ? toTask(row) : null;
}

function removeForUser(id, userId) {
  const result = database
    .prepare("DELETE FROM tasks WHERE id = ? AND user_id = ?")
    .run(id, userId);

  return result.changes > 0;
}

Ikki xil kirish: sessiya va token

Loyihada ikkala yondashuv ham bor va ular aralashmaydi.

Marshrut guruhi Kim uchun Himoya
/tasks, /login (HTML) Brauzer Sessiya + CSRF
/api/* (JSON) Mobil ilova, SPA Authorization: Bearer

Ikkalasi bitta model qatlamiga murojaat qiladi. Farq faqat kirish usulida va javob formatida:

// routes/tasks.js — brauzer uchun
router.get("/", requireAuthPage, (request, response) => {
  const tasks = Task.getAllByUser(request.session.userId);
  response.render("tasks", { pageTitle: "Mening vazifalarim", tasks: tasks });
});

// routes/api.js — mobil ilova uchun
router.get("/tasks", requireToken, (request, response) => {
  response.json(Task.getAllByUser(request.userId));
});

Model funksiyasi bitta — bu ajratishning to’g’ridan-to’g’ri foydasi.

Yakuniy loyiha topshirig’i

Loyihani quyidagi talablar bo’yicha tugating.

Majburiy:

  1. Foydalanuvchi ro’yxatdan o’tadi va kiradi; parol bcrypt bilan hash qilinadi;
  2. Har foydalanuvchi faqat o’z vazifalarini ko’radi, tahrirlaydi va o’chiradi;
  3. Baza tuzilishi migratsiyalar bilan boshqariladi;
  4. SQL faqat models/ ichida yoziladi;
  5. Formalar CSRF tokeni bilan himoyalanadi, chiqish POST bilan bajariladi;
  6. Kirish marshrutida urinishlar soni cheklangan;
  7. Profil rasmi yuklanadi: hajm va tur tekshiriladi, nom tasodifiy;
  8. Kamida oltita test yozilgan va npm test o’tadi;
  9. Sirlar .env da, .env esa .gitignore da.

Qo’shimcha (xohishga ko’ra):

  • /api/* marshrutlari JWT bilan ishlaydi;
  • Vazifalarni muhimlik bo’yicha saralash va filtrlash;
  • Parolni almashtirish sahifasi (eski parol so’raladi);
  • /health marshruti va morgan logi;
  • Sahifalash (?page=2) bilan uzun ro’yxat.

Baholash mezoni

O’z ishingizni shu jadval bo’yicha tekshiring. O’ng ustun — qanday sinash kerakligi.

Mezon Qanday tekshiriladi
Ma’lumot saqlanadi Serverni o’chirib yoqing, ro’yxat joyida qolsin
Parol ochiq emas Bazaga qarang: $2b$10$ bilan boshlansin
Kirmagan kira olmaydi curl bilan /api/tasks401 kelsin
Xato xabari umumiy Yo’q email va xato parol bir xil javob bersin
SQL marshrutda yo’q routes/ da SELECT so’zini qidiring — topilmasin
Migratsiya takrorlanmaydi npm run migrate ni ikki marta yuriting
XSS to’silgan <b>test</b> sarlavhali vazifa qo’shing — qalin chiqmasin
Fayl turi tekshiriladi .txt fayl yuklang — 400 kelsin
Chegaradan katta fayl 5 MB fayl yuklang — 413 kelsin
Rate limit ishlaydi Kirishga olti marta urinib ko’ring — 429 kelsin
Testlar o’tadi npm test — hamma bo’lsin
Egalik tekshiriladi Ikki hisob oching; birinchisining vazifa id sini ikkinchisidan so’rang — 404 kelsin

Oxirgi qator qalin yozilgani bejiz emas. Bu sinov haqiqiy loyihalarda eng ko’p uchraydigan xavfsizlik kamchiligini ochadi va uni qo’lda tekshirmasangiz, hech qachon sezmaysiz.

Bilimni tekshirish

Kodga qaramay javob berishga urinib ko’ring. Har savol yonida — javob yozilgan dars.

  1. Xotiradagi massiv va bazadagi jadval orasidagi asosiy farq nima? (Bazani ulash)
  2. SQL ga qiymatni matn birikmasi bilan qo’shish nega xavfli? (Bazani ulash)
  3. routes/ va models/ orasidagi chegara qanday qoida bilan belgilanadi? (Model qatlami)
  4. Bajarilgan migratsiya faylini nega tahrirlab bo’lmaydi? (Migratsiya)
  5. Cookie’ga userId yozish nega xato? (Sessiya va cookie)
  6. httpOnly bayrog’i qaysi hujumni to’sadi? (Sessiya va cookie)
  7. Bir xil paroldan har safar boshqa hash chiqsa, compare qanday ishlaydi? (Ro’yxatdan o’tish)
  8. Kirish xatosida nega “email topilmadi” deb yozilmaydi? (Kirish va himoya)
  9. 401 va 403 qachon ishlatiladi? (Kirish va himoya)
  10. JWT payload’iga parol solish nega xato? (JWT va API token)
  11. Yuklangan faylga nega foydalanuvchi bergan nom berilmaydi? (Fayl yuklash)
  12. <%= %> va <%- %> farqi qaysi hujumga bog’liq? (Xavfsizlik)
  13. request.agent(app) oddiy request(app) dan nimasi bilan farq qiladi? (Testlash)
  14. trust proxy yoqilmasa nima jimgina buziladi? (Deploy)

Javobi darhol esga kelmagan savol bo’lsa, o’sha darsga qayting — bu bilimdagi bo’shliqni topishning eng tez yo’li.

Xatolar ro’yxati

Bu bo’limda talabalar ko’p takrorlaydigan xatolar. Loyihangizni topshirishdan oldin har birini tekshiring.

Xato Alomati
session() requireAuth dan keyin ulangan Cannot read properties of undefined (reading 'userId')
await bcrypt.hash da await yo’q Bazada [object Promise], hech kim kira olmaydi
enctype yozilmagan request.file undefined
.get() natijasi tekshirilmagan Cannot read properties of undefined
async marshrutda try/catch yo’q So’rov osilib qoladi, terminalda UnhandledPromiseRejection
secure: true localhost da Sessiya umuman ishlamaydi
Migratsiya pm2 reload dan keyin Yangi kod eski bazaga murojaat qiladi
Model so’rovida user_id sharti yo’q Foydalanuvchi o’zganing ma’lumotini ko’radi

Loyihani kengaytirish

Ilova ishlagach, keyingi qadamlar uchun g’oyalar:

  • Vazifa bo’limlaricategories jadvali va bog’lanish;
  • Birgalikda ishlash — vazifani boshqa foydalanuvchiga ulashish;
  • Email tasdiqlash — ro’yxatdan o’tgandan keyin havola yuborish;
  • Sahifalash va qidiruv?search=kitob&page=2;
  • PostgreSQL’ga o’tish — faqat db/ va models/ o’zgaradi;
  • TypeScriptNode.js va TypeScript darsi bilan.

Beshinchi band ayniqsa qiziq: agar model qatlami to’g’ri ajratilgan bo’lsa, marshrutlarga umuman qo’l tegmaydi. Bu ajratishning haqiqiy sinovi.

Yo’l qayerga olib keldi

Bo’lim boshida express() funksiyasi va bitta app.get() bor edi. Hozir sizda foydalanuvchi hisoblari, hash qilingan parollar, migratsiyali baza, fayl yuklash, xavfsizlik qatlamlari, avtomatik testlar va serverga chiqarish rejasi bor ilova turibdi.

Bu ro’yxatdagi hech narsa Express’ga xos emas. Model qatlami, migratsiya, sessiya, token, CSRF, rate limiting — bular hamma backend frameworkida bir xil ataladi va bir xil ishlaydi. Nest.js, Fastify yoki boshqa tilga o’tsangiz, sintaksis o’zgaradi, tushunchalar esa qoladi.

Loyihani git bilan saqlang va README.md yozing: ilova nima qiladi, qanday ishga tushiriladi, qaysi muhit o’zgaruvchilari kerak. Bu fayl loyihani ish beruvchiga ko’rsatganingizda birinchi o’qiladigan narsa bo’ladi — va u sizning kodingiz haqida kod yozgan narsangizdan kam gapirmaydi.

Bu dars foydali bo'ldimi?

marta ko'rildi