Модуль 27

Динамічні маршрути та параметри

Ось готовий урок, створений спеціально за твоїм запитом у стилі CS50.


🎓 Урок: Динамічні маршрути та параметри

(Web Development / Backend logic)


1. 🔥 Вступ: Проблема мільйона сторінок

Уявіть, що ви створюєте наступний Amazon або Rozetka. У вас у базі даних є 100 000 товарів: кросівки, ноутбуки, книги, корм для котів.

Ви створюєте сторінку для першого товару і називате її /product-1. Чудово. Потім для другого — /product-2. Потім для третього...

Стоп. Чи справді ви збираєтесь вручну прописувати 100 000 маршрутів у своєму коді?

// Це пекло розробника:
app.get('/product-1', (req, res) => { ... });
app.get('/product-2', (req, res) => { ... });
app.get('/product-3', (req, res) => { ... });
// ... ще 99 997 рядків ...

Це неможливо підтримувати. А що, коли додається новий товар? Вам потрібно лізти в код і дописувати новий рядок? Звісно, ні.

Аналогія з життя: паспорти. Держава не друкує окремий унікальний бланк паспорта для кожного громадянина окремо з нуля. Існує один шаблон, у якому є пусті місця: «Ім'я», «Прізвище», «Дата народження». Коли ви отримуєте паспорт, у цей шаблон просто підставляються ваші дані.

У веб-розробці ми робимо те саме. Нам потрібен один маршрут-шаблон, який зможе обробити будь-який товар. Ось тут на сцену виходять динамічні параметри.


2. 🧠 Теоретична база: Шаблони замість хардкоду

Що таке динамічний маршрут?

Динамічний маршрут — це адреса, частина якої є змінною. Ми не знаємо заздалегідь, що там напише користувач, але ми готові це обробити.

У більшості фреймворків (Express.js, Django, Ruby on Rails, React Router) динамічна частина позначається двокрапкою :.

Схема виглядає так: GET /products/:id

Де :id — це плейсхолдер (змінна).

Як це працює «під капотом»?

Коли сервер отримує запит, він поводиться як розумний бібліотекар:

  1. Приходить запит: GET /products/42.
  2. Сервер сканує список маршрутів.
  3. Він бачить шаблон /products/:id.
  4. Він порівнює:
    • /products/ співпадає з /products/.
    • Ага! Далі йде змінна :id.
    • Значить, 42 — це і є значення для id.
  5. Сервер кладе це значення в спеціальний об'єкт (зазвичай називається params) і передає вам.

❗️ Що треба запам’ятати: * Двокрапка : перетворює частину URL на змінну. * Все, що користувач введе на цьому місці, стане доступним у коді.


3. 🧪 Приклади: Від простого до складного

(Приклади наведені на синтаксисі Express.js, але логіка універсальна)

Рівень 1: Привіт, незнайомцю

Уявімо, ми хочемо вітати користувача по імені.

Код:

app.get('/hello/:name', (req, res) => {
    const userName = req.params.name; // Витягуємо параметр
    res.send(`Привіт, ${userName}!`);
});

🧐 Питання до вас: Що побачить користувач, якщо перейде за посиланням /hello/Oleg? А якщо /hello/Maria?

Результат: * /hello/Oleg -> "Привіт, Oleg!" * /hello/Maria -> "Привіт, Maria!"

Система одна, результати різні. Елегантність!


Рівень 2: Реальний кейс (Блог)

У нас є масив статей (у реальності це була б база даних).

Код:

const posts = {
    1: "Це пост про JavaScript",
    2: "Це пост про Python",
    3: "Чому CS50 такий крутий"
};

app.get('/posts/:id', (req, res) => {
    const id = req.params.id;
    const content = posts[id]; // Шукаємо пост за ID

    if (content) {
        res.send(content);
    } else {
        res.send("Пост не знайдено 😢");
    }
});

🧐 Питання: Що буде, якщо я введу /posts/5?

Пояснення: Сервер зловить число 5 у змінну id. Він спробує знайти posts[5]. Там нічого немає (undefined). Спрацює else, і ми побачимо "Пост не знайдено". Це і є найпростіша обробка помилок 404.


Рівень 3: Множинні параметри (Inception)

Іноді нам потрібно більше деталей. Наприклад, ми хочемо знайти конкретний коментар до конкретного посту.

Маршрут: /posts/:postId/comments/:commentId

Запит: /posts/10/comments/5

Що всередині req.params?

{
  postId: "10",
  commentId: "5"
}

Тепер ми точно знаємо, що шукати.


4. 🛠 Практична частина

Час забруднити руки кодом. Уявіть, що ви пишете бекенд.

Завдання 1: "Ехо"

Напишіть маршрут /echo/:word, який просто повертає користувачеві те саме слово, яке він написав, але великими літерами (наприклад, /echo/hello -> "HELLO").

Завдання 2: Проста арифметика

Створіть маршрут /sum/:a/:b. Якщо я переходжу за /sum/10/5, я маю отримати відповідь "Сума: 15". (Підказка: параметри приходять як рядки, не забудьте перетворити їх у числа!)

Завдання 3: Профіль користувача

У вас є об'єкт:

const users = {
    "john": "Developer",
    "jane": "Designer"
};

Створіть маршрут /profile/:username. * Якщо юзер є — пишіть "John is a Developer". * Якщо немає — "User not found".

Завдання 4: Міні-кейс "Календар"

Придумайте маршрут для перегляду подій за конкретну дату. Які параметри вам потрібні в URL? (Варіант: /calendar/:year/:month/:day).

Завдання 5: А що, якщо... (Bug hunting)

Ви написали такий код:

app.get('/users/new', (req, res) => { res.send("Створення нового юзера"); });
app.get('/users/:id', (req, res) => { res.send("Перегляд ID: " + req.params.id); });

А тепер поміняйте їх місцями. Поставте /users/:id перед /users/new. Перейдіть за посиланням /users/new. Що станеться? Чому сервер думає, що "new" — це ID користувача?


5. 💡 Мислення як у розробника

Ось що відрізняє новачка від сеньйора в цій темі.

1. Конфлікти маршрутів (Те саме Завдання 5)

Це класична пастка. Сервер читає маршрути зверху вниз. Якщо ви поставите загальний шаблон /users/:id вище, ніж конкретний /users/new, то запит new потрапить у пастку шаблону. Сервер подумає: "О, new — це просто такий дивний ID". Правило: Специфічні (конкретні) маршрути завжди ставте вище за динамічні.

2. Безпека та валідація

Ніколи не довіряйте тому, що прийшло в параметрах. Якщо ви очікуєте ID товару (число), а вам надіслали /products/hacker-script, ваш код не повинен впасти. Профі-рада: Завжди перевіряйте: "Це число?", "Чи існує такий запис у базі?", перш ніж робити щось серйозне.

3. Неймінг

Називайте параметри зрозуміло. Погано: /shop/:p/:c Добре: /shop/:productId/:commentId Код читають люди, а не тільки комп'ютери.


6. 🧩 Підсумок

Отже, що ми сьогодні зробили? 1. Зрозуміли, що створювати статичні сторінки для кожного елемента — це тупиковий шлях. 2. Навчилися використовувати параметри (двокрапка :) як змінні в URL. 3. З'ясували, як отримувати ці дані в коді (req.params). 4. Навчилися уникати конфліктів маршрутів.

Тепер ви вмієте: створювати один маршрут, який може обслуговувати мільйони різних запитів. Ви перетворили свій код із жорсткого каменю на гнучку глину.

🔍 Тизер наступного уроку: Ми навчилися передавати обов'язкові дані (наприклад, ID товару). Але що, якщо ми хочемо відфільтрувати товари? Наприклад, показати тільки червоні кросівки або сортувати від дешевих до дорогих? Тут параметри шляху не підходять. На наступному занятті ми розберемо Query String (рядки запиту) — ті самі штуки після знаку питання ?sort=price&color=red.

А тепер — за код! 🚀