Довгий час JavaScript був мовою, яка жила виключно в одному місці — у браузері користувача. Він вчився лише керувати кнопками, малювати анімації і валідувати форми. Якщо вам потрібен був Сервер (Backend), який міг би зберігати дані в базу, авторизувати користувачів та обробляти платежі, вам доводилося вчити зовсім іншу мову: PHP, Python, Java або Ruby.
Але у 2009 році світ перекинула технологія Node.js. Вона дозволила “витягнути” рушій JavaScript з браузера і встановити його прямо на серверну операційну систему (Windows, Linux, macOS). Раптом JavaScript отримав можливість працювати з комп’ютером на низькому рівні: читати файли на диску, відкривати мережеві порти, звертатися до баз даних.
Це створило еру Full-stack JavaScript розробки (MERN-стек). Тепер розробник міг написати весь проект від початку до кінця на одній мові — JS.
Мета цієї лекції — зрозуміти, що таке серверний JS, навчитися піднімати власний сервер та створювати власне API за допомогою фреймворку Express.
Node.js — це середовище виконання (runtime environment). Воно побудоване на основі двигуна V8, який розробляє компанія Google (саме на ньому працює браузер Google Chrome).
Node.js написаний на мові C++. Він бере ваш JS-код, компілює його у надшвидкий машинний код і дозволяє йому виконуватися прямо в операційній системі.
Головні особливості Node.js:
Оскільки Node.js немає доступу до document чи window (бо немає браузера і DOM!), у нього є свої вбудовані “суперсили” — глобальні модулі (наприклад fs - File System, http, path).
Приклад читання текстового файлу з жорсткого диска комп’ютера:
// Старий формат імпорту (CommonJS), що досі часто використовується в Node.js
const fs = require("fs");
// Читаємо файл асинхронно
fs.readFile("message.txt", "utf8", (err, data) => {
if (err) {
console.error("Помилка читання файлу:", err);
return;
}
console.log("Вміст файлу: ", data);
});
Останні версії Node.js підтримують і сучасний синтаксис import/export (ES Modules), до якого ми звикли у React. Для цього в конфігураційному файлі проекту package.json потрібно вказати "type": "module".
Сервер — це комп’ютер, який працює 24/7, підключений до Інтернету та постійно “слухає” певний порт (наприклад, 80 для HTTP, або 443 для HTTPS). Його задача: прийняти Запит (Request) від Клієнта (браузера або мобільного додатку), зрозуміти, що хоче Клієнт, зробити розрахунки і повернути Відповідь (Response).
Node.js вміє створювати сервери за допомогою вбудованого модуля http, але код виходить дуже довгим і низькорівневим (доводиться вручну перевіряти URL-рядок, вирізати потрібні шматки URL, розбирати кожен HTTP-заголовок).
Щоб не винаходити велосипед, 95% розробників використовують фреймворк абстракції — Express.js.
Express.js — це мінімалістичний, гнучкий веб-фреймворк для Node.js. Завдяки йому написати повноцінний сервер, який може віддавати JSON та обробляти запити користувачів, можна всього в 10 рядків коду. Він бере на себе всю важку роботу з маршрутизацією та обробкою помилок.
Ініціалізація проекту:
npm init -y # Створює package.json (паспорт проекту)
npm install express # Встановлює фреймворк
Створимо файл index.js. Ось вичерпний код для створення справжнього HTTP-сервера:
// 1. Підключаємо Express
const express = require("express");
// 2. Створюємо "додаток" (екземпляр сервера). Його традиційно називають app.
const app = express();
const PORT = 3000; // На якому порту буде "жити" сервер
// 3. Створюємо перший маршрут (Route).
// Коли хтось зробить GET-запит на головну сторінку ('/'), запуститься ця функція
app.get("/", (req, res) => {
// res.send - це зручна команда Express для відправки текстової відповіді
res.send("Привіт, Світ! Це мій перший бекенд.");
});
// 4. Запускаємо сервер: він починає "слухати" порт
app.listen(PORT, () => {
console.log(`Сервер успішно запущено на http://localhost:${PORT}`);
});
Тепер, якщо ми відкриємо термінал і виконаємо node index.js, сервер “оживе”. Ми зможемо відкрити вкладку браузера на адресі http://localhost:3000 і побачити наш текст.
Звісно, сервер зазвичай має обслуговувати не один URL, а десятки різних шляхів.
В Express ми прив’язуємо Логіку до HTTP Методу (GET, POST, DELETE) та Шляху (/users, /products).
Як ми згадували в лекції про REST API:
app.get() — для читання даних.app.post() — для додавання нових даних (наприклад, з форми реєстрації).app.delete() — для видалення.Кожен такий обробник завжди приймає два важливі аргументи: req (Request/Запит) та res (Response/Відповідь).
req лежать всі дані, з якими до нас прийшов клієнт (наприклад, яка в нього IP адреса, який у нього токен авторизації, які додаткові параметри він передав у URL).res лежать функції, якими ми користуємося, щоб відправити клієнту результат і завершити транзакцію (наприклад res.json(), res.status(404)).Створення найпростішого REST API (Повертаємо JSON):
// Імітуємо базу даних у пам'яті
const users = [
{ id: 1, name: "Олександр", role: "admin" },
{ id: 2, name: "Марія", role: "user" },
];
// Коли React-додаток (або Postman) звернеться до localhost:3000/api/users
app.get("/api/users", (req, res) => {
// Замість res.send() (який віддає текст/html), використовуємо res.json()
// Він автоматично перетворить масив JS у формат JSON і відправить клієнту
res.json(users);
});
Динамічні URL (як у React Router): Як знайти одного конкретного користувача?
// Двокрапка :id перетворює цю частину шляху на змінну (параметр)
app.get("/api/users/:id", (req, res) => {
// Всі такі змінні лежать в об'єкті req.params
const userId = Number(req.params.id);
// Шукаємо користувача масиві
const user = users.find((u) => u.id === userId);
if (!user) {
// Якщо не знайшли - ставимо статус 404 (Not Found)
return res.status(404).json({ error: "Користувача не знайдено" });
}
// Все добре (статус 200 ставиться автоматично), віддаємо юзера
res.json(user);
});
Middleware (Мідлвари) — це серце філософії Express.
Мілвар — це функція, яка має доступ до об’єкта запиту (req) і об’єкта відповіді (res), і запускається між тим моментом, як запит прийшов на сервер, і тим моментом, як спрацює ваш фінальний роут (наприклад app.get('/users')).
Нащо вони потрібні? Для обробки “чорнової роботи”, що повторюється для ВСІХ або декількох вибраних маршрутів. Приклади Middleware:
"Отримано запит GET /api/users о 14:00").Глобальний Мідлвар логування (Виконується для будь-якого запату):
// Слово "use" означає "використати мідлвар"
app.use((req, res, next) => {
console.log(`[ЛЗГ] Новий запит: Метод ${req.method} на адресу ${req.url}`);
// next() - КРИТИЧНО ВАЖЛИВА функція. Вона каже Express-у:
// "Я закінчив свою проміжну роботу, передаю естафету наступній функції (вашому роуту)".
// Якщо не викликати next() - клієнт зависне (буде чекати вічно).
next();
});
Вбудований Мідлвар для POST-запитів:
За замовчуванням Express не вміє читати JSON, який присилає йому React-додаток при відправці форм. Щоб навчити його, достатньо одного рядка (це вбудований мідлвар):
app.use(express.json()); // Вчить Express збирати JSON з тіла запиту і класти його в req.body
Тепер ми можемо обробляти POST запити (створення):
app.post("/api/users", (req, res) => {
// В req.body лежать нові дані від клієнта (наприклад { name: "Іван", role: "user" })
const newUser = req.body;
// Генеруємо новий ID для бази
newUser.id = users.length + 1;
users.push(newUser);
// Відповідаємо статусом 201 (Created)
res.status(201).json(newUser);
});
app.get(), app.post(), app.delete().req — містить урл-параметри, тіло повідомлення, заголовки) та Об’єкта Відповіді (res — керує HTTP-статусами та відправкою даних через команду res.json()).app.use(express.json())).npm і яку роль цей концепт відіграє в екосистемі Node?Express замість того, щоб масувати обробку запитів голим Node.js модулем “http”?next)?GET запит вигляду /users/99. Як називається об’єкт (його поле), всередині якого лежить число 99, і як з ним працює Express-навігація (req.xxx...)?app.js, щоб об’єкт req.body не був undefined?