gadget59.ru лекция
Express · Лекция 37 · 28 слайдов

Лекция №37: Node.js + Express + MS SQL Server: создаем API на Windows

От скрипта к API (на Windows)

В прошлой лекции (№36) мы написали скрипт, который сам стучался в базу данных. Но настоящие сайты работают иначе. Сайт — это сервер, который ждет команды от пользователя.

API (Application Programming Interface) — это «меню» нашего сервера. Пользователь (через браузер) заказывает блюдо (например, «дай мне список книг»), а сервер приносит результат.

🟨 Node.js 📦 Express 🪟 MS SQL Server 📡 HTTP 📄 JSON
Сегодня мы превратим наш скрипт в полноценный веб-сервер. Он будет слушать порт 3000 и отвечать на запросы через Командную строку Windows.
Формат: лекция-практика. Мы установим Express и подружим его с нашей базой «Библиотека», используя Windows-пути.

План лекции

Мы построим фундамент для сайта нашей библиотеки.

  • 1 Что такое Express и зачем он нужен
  • 2 Командная строка Windows (cmd) и навигация
  • 3 Установка Express и первый запуск сервера
  • 4 Что такое HTTP-запросы (GET, POST)
  • 5">Роуты (пути): /books, /readers
  • 6 Подключение MS SQL Server к Express
  • 7 JSON: язык общения сервера и клиента
  • 8 Обработка ошибок 404 и 500
  • 9 Запуск: npm start в Windows
  • 10 Практика и домашнее задание
Express — это самая популярная «коробка с инструментами» для Node.js. Без него создание сайта превращается в мучение.

Что такое Express?

Express — это веб-фреймворк для Node.js. Это набор готовых функций, которые помогают принимать запросы из интернета и отправлять ответы.

Браузер
→
HTTP-запрос
→
Express
→
MS SQL Server
  • Node.js — это двигатель (он умеет запускать JS).
  • Express — это руль, педали и кузов. Без них двигатель просто шумит на месте.
Express берет на себя всю рутину: разбор адресов, чтение данных из форм, отправку правильных заголовков. Мы пишем только логику.

Установка Express

Откройте Командную строку (cmd) или PowerShell в папке вашего проекта (где лежат файлы из лекции 36) и выполните:

npm install express

Также нам понадобится morgan — он будет записывать в консоль каждый входящий запрос (очень удобно для отладки).

npm install morgan
Убедитесь, что в папке есть файл package.json. Если его нет, создайте его командой npm init -y.

Первый сервер (файл server.js)

Создайте файл server.js. Это главная точка входа нашего сайта.

const express = require('express'); const morgan = require('morgan'); const app = express(); // Morgan будет писать в консоль: GET /books 200 15ms app.use(morgan('dev')); app.get('/', (req, res) => { res.send('Сервер библиотеки работает! 🚀'); }); const PORT = 3000; app.listen(PORT, () => { console.log(`Сервер запущен на http://localhost:${PORT}`); });
Запустите node server.js. Откройте в браузере http://localhost:3000. Вы увидите текст.

Что такое HTTP и REST?

HTTP (HyperText Transfer Protocol) — это правила, по которым браузер и сервер общаются.

GET
Получить
Просмотр списка книг.
POST
Создать
Добавление нового читателя.
PUT
Изменить
Редактирование email.
DELETE
Удалить
Удаление записи.

REST — это соглашение о том, как называть адреса (роуты).

GET /books // все книги GET /books/5 // книга с ID 5 POST /books // создать книгу

Роуты (Маршруты)

Роут — это адрес и функция, которая на него отвечает. Давайте добавим книги.

app.get('/books', (req, res) => { res.send('Здесь будет список всех книг'); }); app.get('/readers', (req, res) => { res.send('Здесь будет список читателей'); });
Теперь по адресу localhost:3000/books браузер покажет список книг, а по /readers — читателей. Это и есть API.

Подключаем базу данных

Нам больше не нужен файл index.js из прошлой лекции. Мы перенесем логику работы с SQL прямо в роуты Express.

Убедитесь, что установлен пакет mssql и есть файл .env с настройками.

npm install mssql
Мы будем использовать тот же пул соединений, который настраивали в лекции 36, но запускать его будем вместе с сервером.

Модуль db.js (настройка пула)

Создадим файл db.js, который будет хранить настройки подключения. Это хорошая практика — не писать пароль в главном файле.

require('dotenv').config(); const sql = require('mssql'); const config = { server: process.env.DB_SERVER, database: process.env.DB_DATABASE, user: process.env.DB_USER, password: process.env.DB_PASSWORD, options: { encrypt: false } }; let pool; async function initDb() { pool = await sql.connect(config); console.log('✅ База данных подключена к Express'); } module.exports = { initDb, pool };
Важно для Windows: В файле .env путь к серверу для Express пишется с ДВОЙНЫМ обратным слэшем: DB_SERVER=localhost\\SQLEXPRESS. Если написать один слэш, Node.js может выдать ошибку.

Роут: GET все книги (связка с SQL)

Теперь заставим адрес /books реально ходить в базу данных MS SQL Server. Для этого нам нужно импортировать наш модуль db.js в файл server.js.

const db = require('./db'); // Запускаем сервер только после подключения к БД db.initDb().then(() => { // Роуты пишем здесь, чтобы pool уже существовал app.get('/books', async (req, res) => { try { const result = await db.pool.request() .query('SELECT Id, Title, Year FROM Books ORDER BY Title'); // Отправляем данные в формате JSON res.json(result.recordset); } catch (err) { console.error(err); res.status(500).json({ error: 'Ошибка базы данных' }); } }); const PORT = 3000; app.listen(PORT, () => { console.log(`Сервер запущен на http://localhost:${PORT}`); }); }).catch(err => { console.error('Не удалось подключиться к БД:', err); process.exit(1); });
Если вы откроете в браузере localhost:3000/books, вы увидите не текст, а структурированные данные (JSON) со списком книг из вашей таблицы Books.

Что такое JSON?

JSON (JavaScript Object Notation) — это текстовый формат обмена данными. Это «язык», на котором сервер и браузер понимают друг друга.

// Это объект JavaScript { name: "Иван", age: 20 } // А это JSON (строка) "{ \"name\": \"Иван\", \"age\": 20 }"

Когда мы пишем res.json(data), Express сам превращает наш массив книг в такую строку и добавляет правильный заголовок Content-Type: application/json.

Браузер получает эту строку и понимает: «Ага, это список книг, я могу нарисовать их в таблице или передать дальше».

Роут: GET книга по ID (параметры)

Как показать одну конкретную книгу? Используем двоеточие в адресе — это «параметр маршрута».

app.get('/books/:id', async (req, res) => { const bookId = req.params.id; const result = await db.pool.request() .input('Id', sql.Int, bookId) .query('SELECT * FROM Books WHERE Id = @Id'); if (result.recordset.length === 0) { return res.status(404).json({ error: 'Книга не найдена' }); } res.json(result.recordset[0]); });
Адрес localhost:3000/books/5 положит число 5 в переменную req.params.id. Мы ОБЯЗАТЕЛЬНО передаем его через input(), чтобы защититься от SQL-инъекций.

Роут: POST новый читатель (тело запроса)

Чтобы добавить данные, клиент (браузер или Postman) присылает их в «теле» запроса. Но Express не умеет читать тело сам — ему нужен специальный «переводчик» express.json().

// В самом верху server.js, ДО роутов: app.use(express.json()); app.post('/readers', async (req, res) => { const { name, email } = req.body; const result = await db.pool.request() .input('Name', sql.NVarChar, name) .input('Email', sql.NVarChar, email) .query('INSERT INTO Readers (Name, Email) OUTPUT INSERTED.Id VALUES (@Name, @Email)'); res.status(201).json({ id: result.recordset[0].Id }); });
Важно: Без строчки app.use(express.json()) вверху файла переменная req.body будет пустой (undefined), и вы не сможете прочитать имя и почту читателя.

Middleware (Промежуточное ПО)

Middleware — это функции, которые выполняются до нашего роута. Это как конвейер на заводе или фильтры в Instagram.

Запрос
→
morgan (логирует)
→
express.json() (парсит тело)
→
Наш роут (дает ответ)
→
Ответ клиенту

Мы уже использовали middleware: app.use(morgan) и app.use(express.json()). Они подготавливают запрос для нас.

Роуты в отдельном файле (пример books.js)

Файл server.js становится огромным. Пора разделить его. Хороший проект для Windows выглядит так:

C:\Users\Имя\Documents\library-api\ ├── server.js // запуск сервера ├── db.js // подключение к SQL └── routes\ └── books.js // все роуты /books

Создаем папку routes и файл books.js внутри неё.

const express = require('express'); const sql = require('mssql'); const db = require('../db'); const router = express.Router(); router.get('/', async (req, res) => { try { const result = await db.pool.request() .query('SELECT Id, Title, Year FROM Books ORDER BY Title'); res.json(result.recordset); } catch (err) { res.status(500).json({ error: err.message }); } }); router.get('/:id', async (req, res) => { try { const result = await db.pool.request() .input('Id', sql.Int, req.params.id) .query('SELECT * FROM Books WHERE Id = @Id'); res.json(result.recordset[0]); } catch (err) { res.status(500).json({ error: err.message }); } }); module.exports = router;

Правила безопасного API

Запомните эти правила — они защитят сервер от взлома.

  1. Никаких конкатенаций строк в SQL. Только request.input() и @параметры.
  2. Валидация входящих данных. Если ждете число (ID), проверьте, что это число. Библиотека express-validator поможет.
  3. Ограничение прав. Не все могут удалять книги. Проверяйте права пользователя (middleware авторизации).
  4. Лимиты (Rate Limiting). Чтобы один пользователь не мог «уронить» сервер тысячей запросов в секунду.
  5. Заголовки безопасности. Используйте пакет helmet (он сам настроит правильные заголовки HTTP).
  6. Не отдавайте лишнего. Если в таблице Readers есть пароль (хэш), не возвращайте его в res.json().
SQL-инъекция в API — это самая частая причина утечек данных. Параметризованные запросы обязательны.

Итоговый server.js (сборка)

Посмотрите, как аккуратно выглядит главный файл после рефакторинга:

const express = require('express'); const morgan = require('morgan'); const booksRouter = require('./routes/books'); const db = require('./db'); const app = express(); app.use(morgan('dev')); app.use(express.json()); // Сначала подключаем БД db.initDb().then(() => { app.use('/books', booksRouter); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`API запущено на http://localhost:${PORT}`); }); }).catch(err => { console.error('База не подключена:', err); process.exit(1); });

Типичные ошибки при запуске в Windows

1. EADDRINUSE (Адрес уже используется)
Порт 3000 занят. Либо старый сервер не выключился (в Диспетчере задач), либо там висит Skype или другой сервис.
2. Cannot find module
Забыли установить пакет (npm install express) или опечатались в названии папки routes (в Windows важен регистр, если сервер на Linux, но локально в cmd обычно нет, однако в коде путь должен совпадать).
3. req.body is undefined
Забыли написать app.use(express.json()) в server.js.
4. Login failed for user
Файл .env не считан или в нем ошибка. Проверьте, что require('dotenv').config() стоит в самом верху db.js.
5. CORS error
Браузер блокирует запрос, потому что сайт (например, фронтенд на React) и API (наш Node.js) работают на разных портах. Нужен пакет cors.

Тестирование API (Postman / Thunder Client)

Браузер хорошо показывает GET запросы, но для POST и PUT нужны специальные инструменты, где можно писать тело запроса.

  • Postman: отдельная программа для тестирования API.
  • Thunder Client: расширение для VS Code (самый удобный вариант для студентов, всё под рукой).
GET
Проверка списка
localhost:3000/books
POST
Создание
JSON в Body
Научите студентов сохранять коллекции запросов в Thunder Client. Это их «журнал экспериментов», который можно сдать вместе с отчетом.

Практический результат

Вот что вы получите в итоге работы сервера.

// Ответ сервера на GET /books [ { "Id": 1, "Title": "Война и мир", "Year": 1869 }, { "Id": 2, "Title": "Мастер и Маргарита", "Year": 1967 } ] // Ответ на POST /readers (успешное создание) { "id": 15 } // Ответ при ошибке 404 { "error": "Ресурс не найден", "path": "/blabla" }
Вы создали настоящий Backend. К этому серверу теперь можно подключить любой сайт, мобильное приложение или Telegram-бота.

Самостоятельные задания

Доработайте API «Библиотека».

  1. Роут PUT /readers/:id: изменение данных читателя (например, email). Используйте req.body.
  2. Роут DELETE /books/:id: удаление книги (мягкое удаление — поставить в SQL флаг IsDeleted = 1).
  3. Поиск: роут GET /books/search?title=война (используйте req.query.title и WHERE Title LIKE '%' + @title + '%').
  4. Выдача книги: роут POST /loans, который принимает { bookId, readerId } и проверяет в SQL, что книга не занята.
  5. Валидация: добавьте проверку, что в POST /readers email выглядит как email (используйте пакет express-validator).
Для PUT и POST не забывайте писать app.use(express.json()) в начале server.js.

Итоги лекции

Что мы теперь умеем:

  • ✅ Express: создание веб-сервера и роутов.
  • ✅ HTTP: понимание методов GET, POST, статус-кодов 200, 404, 500.
  • ✅ JSON: формат обмена данными.
  • ✅ Middleware: express.json() и morgan.
  • ✅ SQL + Node.js: безопасные запросы через mssql внутри асинхронных роутов.
  • ✅ Структура: разделение кода на routes, db.js и server.js.
  • ✅ REST API: создание интерфейса для взаимодействия программ.
Вы прошли путь от «Hello World» до полноценного сервера базы данных. Это 80% навыков backend-разработчика.

Домашнее задание

Задания для сдачи практической работы №37.

  1. Реализуйте все 5 пунктов из «Самостоятельных заданий».
  2. Добавьте роут GET /stats, который возвращает количество книг, читателей и активных выдач (используйте COUNT и GROUP BY в одном запросе).
  3. Настройте package.json так, чтобы сервер запускался командой npm start.
  4. Напишите в отчете: чем отличается синхронный код (как в Java) от асинхронного кода в Express (приведите пример одного и того же действия — получения списка).
  5. Сделайте скриншот окна Thunder Client или Postman с выполненным запросом POST /readers (код состояния 201).
Для пункта 4 вспомните: в Java программа ждет строку stmt.executeQuery(), а в Node.js она идет дальше и ждет «коллбэк» или await.

Спасибо за работу!

📡

API готово к бою!

Вы создали сервер, который понимает язык интернета. Теперь ваша база «Библиотека» доступна не только через SSMS, но и через HTTP-запросы.

🟨 Node.js 📦 Express 🪟 MS SQL Server 📡 REST API 🚀 backend