Router — alohida fayllarga bo'lish, modullar

~20 daq · Express · Middleware

Muammodan boshlaylik

Loyiha o'sib boradi. app.js faylida foydalanuvchilar, mahsulotlar, buyurtmalar, to'lovlar — barchasi bir joyda:

app.get('/users', ...);
app.post('/users', ...);
app.get('/users/:id', ...);
app.put('/users/:id', ...);
app.delete('/users/:id', ...);

app.get('/products', ...);
app.post('/products', ...);
// ... yana 50 ta route

Bir fayl — 500 qator. Qaysi route qayerda ekanini topish qiyin. Jamoa bilan ishlashda har kim bir xil faylni o'zgartiradi — konfliktlar ko'p.

Router bu muammoni hal qiladi: har bir resurs uchun alohida fayl, alohida router.


Router nima?

express.Router() — mini Express ilovasi. Unga route va middleware qo'shiladi, keyin asosiy app ga ulanadi.

Hayotiy o'xshatma: katta kompaniyada har bir bo'lim o'z ichki qoidalariga ega. HR bo'limi — o'z jarayonlari, moliya bo'limi — o'z jarayonlari. Direktor (app) ularni birlashtiradi, lekin har bir bo'lim mustaqil ishlaydi. Router — o'sha bo'lim.


Router yaratish

// routes/users.js
const express = require('express');
const router  = express.Router();

router.get('/', (req, res) => {
  res.json([{ id: 1, name: 'Ali' }]);
});

router.get('/:id', (req, res) => {
  res.json({ id: req.params.id });
});

router.post('/', (req, res) => {
  res.status(201).json(req.body);
});

module.exports = router;
// app.js
const express      = require('express');
const usersRouter  = require('./routes/users');
const app          = express();

app.use(express.json());
app.use('/users', usersRouter); // /users prefiksi bilan ulash

app.listen(3000);

Endi usersRouter dagi barcha route lar /users prefiksi bilan ishlaydi:

  • router.get('/') → GET /users
  • router.get('/:id') → GET /users/:id
  • router.post('/') → POST /users

Router ichida /users yozilmaydi — prefiks app.use da bir marta beriladi.


Loyiha tuzilmasi

Router bilan loyiha quyidagi ko'rinishga keladi:

src/
├── routes/
│   ├── users.js
│   ├── products.js
│   └── orders.js
├── controllers/
│   ├── users.controller.js
│   └── products.controller.js
├── middleware/
│   └── auth.js
└── app.js

Har bir fayl — o'z vazifasi. routes/users.js — faqat foydalanuvchi route lari. controllers/users.controller.js — faqat foydalanuvchi logikasi.


Controller — logikani route dan ajratish

Route faylida ham logika yozish mumkin, lekin bu ham o'sib ketadi. Yaxshi amaliyot — route faqat "qaysi handler" ni ko'rsatadi, handler alohida faylda:

// controllers/users.controller.js
const users = [
  { id: 1, name: 'Ali' },
  { id: 2, name: 'Vali' },
];

exports.getAll = (req, res) => {
  res.json(users);
};

exports.getOne = (req, res) => {
  const user = users.find(u => u.id === +req.params.id);
  if (!user) return res.status(404).json({ message: 'Topilmadi' });
  res.json(user);
};

exports.create = (req, res) => {
  const user = { id: Date.now(), ...req.body };
  users.push(user);
  res.status(201).json(user);
};
// routes/users.js
const express    = require('express');
const router     = express.Router();
const controller = require('../controllers/users.controller');

router.get('/',    controller.getAll);
router.get('/:id', controller.getOne);
router.post('/',   controller.create);

module.exports = router;

Route fayli endi faqat "qaysi URL — qaysi handler" ni ko'rsatadi. Logika controller da. Har biri o'z joyida.


Router da middleware

Router ga middleware qo'shilsa — faqat o'sha router dagi route larga ta'sir qiladi:

// routes/admin.js
const express    = require('express');
const router     = express.Router();
const { authenticate, requireRole } = require('../middleware/auth');

// Bu router dagi barcha route lar uchun:
router.use(authenticate);
router.use(requireRole('admin'));

router.get('/stats',   (req, res) => res.json({ users: 100 }));
router.delete('/users/:id', (req, res) => res.json({ deleted: true }));

module.exports = router;
// app.js
app.use('/admin', adminRouter); // /admin/* — hammasi auth + admin rol talab qiladi
app.use('/users', usersRouter); // /users/* — ochiq

/admin/* ga kelgan barcha so'rovlar authenticate va requireRole('admin') dan o'tadi. /users/* esa ochiq.


app.js — tartibli ko'rinish

Barcha router lar ulangandan keyin app.js qisqa va tushunarli bo'ladi:

const express      = require('express');
const morgan       = require('morgan');
const cors         = require('cors');
const usersRouter  = require('./routes/users');
const productsRouter = require('./routes/products');
const ordersRouter = require('./routes/orders');

const app = express();

// Global middleware
app.use(morgan('dev'));
app.use(cors());
app.use(express.json());

// Route lar
app.use('/users',    usersRouter);
app.use('/products', productsRouter);
app.use('/orders',   ordersRouter);

// 404
app.use((req, res) => {
  res.status(404).json({ message: 'Topilmadi' });
});

// Error middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.statusCode || 500).json({ message: err.message || 'Server xatosi' });
});

module.exports = app;

app.js da logika yo'q — faqat sozlash. Har bir resurs o'z faylida.


Tez-tez uchraydigan xatolar

Prefiks ikki marta yozish:

// routes/users.js da:
router.get('/users', ...); // '/users' yozildi

// app.js da:
app.use('/users', usersRouter); // yana '/users'

// Natija: GET /users/users — noto'g'ri!

Router ichida prefiks yozilmaydi — u app.use da bir marta beriladi.

module.exports unutish:

// routes/users.js
const router = express.Router();
router.get('/', ...);
// module.exports = router; — unutildi!

// app.js da:
const usersRouter = require('./routes/users');
app.use('/users', usersRouter); // usersRouter = {} — bo'sh ob'ekt

Xulosa

Router — Express ilovasini kichik bo'laklarga ajratish uchun. Har bir resurs o'z faylida, o'z route lari bilan. app.use('/prefix', router) bilan asosiy ilovaga ulanadi.

Controller — logikani route dan ajratadi. Route faqat "qaysi URL — qaysi handler" ni ko'rsatadi.

Natija: katta loyihada ham har bir fayl kichik, tushunarli va o'z vazifasiga ega.


Keyingi dars

13-dars: PostgreSQL — pg moduli, connection pool