commit 2bbc104000063a9f62042c0c4e23cee5cef76909 Author: Nikolai Papin Date: Fri Dec 12 17:38:53 2025 +0300 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..b986daf --- /dev/null +++ b/README.md @@ -0,0 +1,463 @@ +# Методические указания по разработке Web API на Node.js для школьников + +## Введение +Данные методические указания предназначены для школьников, имеющих базовые навыки работы с HTML/CSS, Git и SSH. Цель курса — освоить основы разработки Web API с использованием Node.js и фреймворка Express за ограниченное время (3 часа на занятие и несколько занятий в семестр). Упор сделан на практические задания с минимально необходимой теорией. + +--- + +## 📘 **Урок 1: Создание репозитория и организации структуры проекта** + +### **Цель урока**: Создать GitHub-репозиторий, организовать структуру проекта и научиться работать с ветками в Git. + +### **Краткая теория**: +- **GitHub** — платформа для хостинга и совместной разработки IT-проектов с использованием системы контроля версий Git. +- **Репозиторий** — хранилище кода и истории его изменений. +- **Ветка (branch)** — изолированная копия проекта для разработки новой функциональности без влияния на основной код (часто называется `main` или `master`). + +### **Практические шаги**: +1. **Создайте репозиторий на GitHub**: + * Авторизуйтесь на [GitHub](https://github.com). + * Нажмите `+` в правом верхнем углу и выберите `New repository`. + * В поле `Repository name` укажите название, отражающее тему вашего API (например, `my-first-api`). + * Оставьте репозиторий публичным (`Public`). + * **Поставьте галочку** `Add a README.md`. Это создаст начальный файл описания проекта. + * Нажмите `Create repository`. + +2. **Клонируйте репозиторий и создайте учебную ветку**: + ```bash + # Склонируйте репозиторий на компьютер + git clone git@github.com:<ваш-логин>/<название-репозитория>.git + cd <название-репозитория> + + # Создайте и переключитесь на новую ветку 'study' + git checkout -b study + # Если в команде двое, каждый создает свою ветку (например, study-ivanov) + # git checkout -b study-фамилия + ``` + +### **Что должно получиться**: +* Создан удаленный репозиторий на GitHub с файлом `README.md`. +* На вашем компьютере есть локальная копия проекта. +* Вы находитесь в новой ветке (`study` или `study-фамилия`), а не в основной (`main`). + +--- + +## 📦 **Урок 2: Инициализация проекта Node.js** + +### **Цель урока**: Создать структуру папок для backend и инициализировать проект Node.js. + +### **Краткая теория**: +- **Node.js** — это среда выполнения JavaScript вне браузера, которая позволяет создавать серверные приложения. +- **package.json** — это файл манифеста проекта Node.js, который содержит его описание, версию, список зависимостей и скриптов. + +### **Практические шаги**: +1. **Создайте папку `backend`** и перейдите в неё: + ```bash + mkdir backend + cd backend + ``` +2. **Инициализируйте проект Node.js**. Используйте флаг `-y`, чтобы принять значения по умолчанию, и `--type=module` для поддержки современного синтаксиса ES-модулей: + ```bash + npm init -y --type=module + ``` + +### **Проверка результата**: +Убедитесь, что в папке `backend` появился файл `package.json`. В его первой строке должно быть указано `"type": "module"`. + +--- + +## 🚀 **Урок 3: Установка фреймворка Express** + +### **Цель урока**: Установить библиотеку Express — популярный фреймворк для создания веб-приложений и API на Node.js. + +### **Краткая теория**: +- **Express** — это минималистичный и гибкий фреймворк, который значительно упрощает создание серверных приложений и маршрутов. +- **Зависимости (dependencies)** — это сторонние библиотеки (пакеты), которые использует ваш проект. Они управляются с помощью `npm` (Node Package Manager). + +### **Практические шаги**: +В папке `backend` выполните команду установки: +```bash +npm install express +``` + +### **Что должно получиться**: +* В файле `package.json` в раздел `"dependencies"` добавится `"express"` с номером версии. +* В проекте появится папка `node_modules`, где хранятся все установленные библиотеки. + +--- + +## 🗑️ **Урок 4: Работа с `.gitignore` и первый коммит** + +### **Цель урока**: Научиться игнорировать ненужные для репозитория файлы и зафиксировать изменения. + +### **Краткая теория**: +- **`node_modules`** — это папка со всеми зависимостями проекта. Её **нельзя** добавлять в Git, так как она очень большая и её можно восстановить командой `npm install`. +- **`.gitignore`** — специальный файл, в котором перечисляются шаблоны файлов и папок, которые Git должен игнорировать. + +### **Практические шаги**: +1. **Создайте файл `.gitignore`** в корне вашего проекта (на одном уровне с папкой `backend`). +2. **Добавьте в него шаблоны**. Вы можете создать базовое содержимое на сайте [gitignore.io](https://www.toptal.com/developers/gitignore). Введите `Node, Windows, VisualStudioCode` и скопируйте сгенерированный текст в ваш файл. +3. **Убедитесь, что в `.gitignore` есть строки**: + ``` + node_modules/ + .env + ``` +4. **Выполните коммит**: + ```bash + # Вернитесь в корень проекта (если вы в папке backend) + cd .. + + # Добавьте все новые файлы в staging area + git add . + + # Зафиксируйте изменения с комментарием + git commit -m "feat: инициализирован проект Node.js с Express, добавлен .gitignore" + ``` + +--- + +## 📄 **Урок 5: Создание базовой структуры сервера** + +### **Цель урока**: Создать основные файлы приложения и понять их роль. + +### **Краткая теория**: +Серверное приложение на Express обычно разделяют на несколько файлов для лучшей организации: +- **`server.js`** — точка входа. Запускает сервер, подключает основные настройки. +- **`app.js`** — ядро приложения. Содержит настройки Express и все маршруты (routes). + +### **Практические шаги**: +1. В папке `backend` создайте папку `src`. +2. Внутри `src` создайте два файла: `app.js` и `server.js`. +3. **В файл `app.js`** пока добавьте только создание экземпляра приложения: + ```javascript + // backend/src/app.js + import express from 'express'; + + const app = express(); + + export default app; // Экспортируем app для использования в server.js + ``` +4. **В файл `server.js`** добавьте код запуска сервера: + ```javascript + // backend/src/server.js + import app from './app.js'; + + const PORT = process.env.PORT || 3000; + + app.listen(PORT, () => { + console.log(`Сервер запущен и слушает порт ${PORT}`); + }); + ``` + +### **Что должно получиться**: +Создана модульная структура приложения. Пока при запуске сервер будет работать, но на любой запрос возвращать ошибку `404`, так как маршруты не определены. + +--- + +## ▶️ **Урок 6: Первый запуск сервера** + +### **Цель урока**: Запустить сервер и убедиться, что он работает, возвращая ожидаемую ошибку. + +### **Практические шаги**: +1. Из папки `backend` выполните команду: + ```bash + node src/server.js + ``` +2. В консоли должно появиться сообщение: `Сервер запущен и слушает порт 3000`. +3. Откройте браузер и перейдите по адресу `http://localhost:3000`. +4. **Вы должны увидеть стандартную страницу ошибки `Cannot GET /`**. Это ожидаемо, так как мы не создали обработчик для корневого маршрута (`/`). +5. Остановите сервер, нажав `Ctrl + C` в терминале. +6. **Выполните коммит**: + ```bash + git add . + git commit -m "feat: создана базовая структура сервера, успешный запуск" + git push origin study # Или study-фамилия + ``` + +--- + +## 🖐️ **Урок 7: Создание первого маршрута (Hello World)** + +### **Цель урока**: Создать простейший обработчик GET-запроса и получить ответ от сервера. + +### **Краткая теория**: +- **Маршрут (route)** — это правило, которое определяет, как сервер будет реагировать на клиентский запрос к определенному URL (конечной точке) и HTTP-методу (GET, POST и т.д.). +- **Обработчик (handler)** — функция, которая принимает запрос (`req`) и формирует ответ (`res`). + +### **Практические шаги**: +1. Откройте файл `backend/src/app.js`. +2. **Добавьте обработчик для корневого маршрута (`/`) перед строкой `export default app;`**: + ```javascript + // Обработчик GET-запроса на корневой URL '/' + app.get('/', (req, res) => { + // Устанавливаем заголовок ответа + res.setHeader('Content-Type', 'text/plain'); + // Отправляем текстовый ответ + res.send('Hello World from my API!'); + }); + ``` +3. Запустите сервер снова (`node src/server.js`) и обновите страницу `http://localhost:3000` в браузере. +4. **Вы должны увидеть надпись `Hello World from my API!`**. +5. **Выполните коммит**. + +--- + +## 🔢 **Урок 8: Работа с параметрами пути (Path Parameters)** + +### **Цель урока**: Научиться создавать динамические маршруты и извлекать данные из URL. + +### **Краткая теория**: +- **Статические маршруты** — это фиксированные адреса, например, `/about` или `/contacts`. Они всегда одинаковы. +- **Динамические маршруты** — это адреса, которые могут меняться. Например, страница профиля с разными именами пользователей: `/user/anna`, `/user/max`. +- **Параметры пути (Path Parameters)** — специальные части URL, которые меняются. В Express они обозначаются двоеточием (`:`), например: `/user/:username`. +- Когда кто-то заходит на `/user/anna`, Express видит `:username` в маршруте и понимает: "вместо `:username` подставлено `anna`". Это значение сохраняется в `req.params`. + +### **Примеры разных параметров**: + +1. **Один параметр**: +```javascript +// Когда заходят на /hello/Максим +app.get('/hello/:name', (req, res) => { + const name = req.params.name; // = "Максим" + res.send(`Привет, ${name}!`); +}); +``` + +2. **Несколько параметров**: +```javascript +// Когда заходят на /book/сказки/5 +app.get('/book/:genre/:page', (req, res) => { + const genre = req.params.genre; // = "сказки" + const page = req.params.page; // = "5" + res.send(`Жанр: ${genre}, Страница: ${page}`); +}); +``` + +3. **Параметр в середине пути**: +```javascript +// Когда заходят на /category/электроника/product/123 +app.get('/category/:categoryName/product/:productId', (req, res) => { + const category = req.params.categoryName; // = "электроника" + const productId = req.params.productId; // = "123" + res.send(`Категория: ${category}, Товар: ${productId}`); +}); +``` + +### **Практические шаги**: +1. В файле `app.js` добавьте маршрут: +```javascript +// Пример запроса: GET http://localhost:3000/double/7 +app.get('/double/:number', (req, res) => { + const input = req.params.number; // Получаем параметр из URL + + // Проверяем, является ли параметр числом + if (!isNaN(input)) { + const number = parseFloat(input); + const result = number * 2; + res.send(`Если удвоить ${number}, получится ${result}`); + } else { + res.status(400).send('Пожалуйста, укажите число. Например: /double/10'); + } +}); +``` + +2. Протестируйте: + - `http://localhost:3000/double/7` → работает + - `http://localhost:3000/double/abc` → ошибка + +--- + +## ➕➖✖️➗ **Урок 9: Практическое задание — Текстовый API-калькулятор** + +### **Цель задания**: Создать простой калькулятор, который принимает числа в URL и возвращает текстовый результат. + +### **Задание**: +Создайте 4 маршрута для основных математических операций. Формат ответа — обычный текст. + +**Маршруты и примеры**: +1. **Сложение**: `GET /api/calc/sum/:a/:b` + - Пример: `GET /api/calc/sum/5/3` + - Ответ: `5 + 3 = 8` + +2. **Вычитание**: `GET /api/calc/subtract/:a/:b` + - Пример: `GET /api/calc/subtract/10/4` + - Ответ: `10 - 4 = 6` + +3. **Умножение**: `GET /api/calc/multiply/:a/:b` + - Пример: `GET /api/calc/multiply/7/2` + - Ответ: `7 * 2 = 14` + +4. **Деление**: `GET /api/calc/divide/:a/:b` + - Пример: `GET /api/calc/divide/15/3` + - Ответ: `15 / 3 = 5` + +### **Как это сделать**: +1. Для каждого маршрута получите параметры из `req.params.a` и `req.params.b` +2. Преобразуйте их в числа: `const num1 = parseFloat(req.params.a)` +3. Выполните операцию +4. Верните ответ в формате: ``res.send(`${num1} + ${num2} = ${result}`)`` + +### **Важно**: +- Пока не нужно проверять, корректные ли данные прислал пользователь +- Используйте шаблонные строки (обратные кавычки) для формирования ответа + +--- + +## ⚠️ **Урок 10: Базовые проверки в калькуляторе** + +### **Цель урока**: Добавить минимальную проверку входных данных. + +### **Задание**: +Доработайте калькулятор из урока 9, добавив две простые проверки: + +1. **Проверка, что оба параметра — числа** +2. **Для деления — проверка, что второй параметр не ноль** + +### **Как это сделать**: + +**Шаг 1: Проверка на число** +В начале каждого обработчика добавьте: +```javascript +const a = parseFloat(req.params.a); +const b = parseFloat(req.params.b); + +// Проверяем, являются ли оба параметра числами +if (isNaN(a) || isNaN(b)) { + return res.status(400).send('Ошибка: оба параметра должны быть числами'); +} +``` + +**Шаг 2: Проверка деления на ноль** +Только в обработчике деления добавьте после проверки на числа: +```javascript +// Проверка деления на ноль +if (b === 0) { + return res.status(400).send('Ошибка: на ноль делить нельзя'); +} +``` + +### **Что должно происходить**: +- `/api/calc/sum/5/3` → `5 + 3 = 8` (работает) +- `/api/calc/sum/5/abc` → `Ошибка: оба параметра должны быть числами` (ошибка 400) +- `/api/calc/divide/10/0` → `Ошибка: на ноль делить нельзя` (ошибка 400) + +--- + +## 📊 **Урок 11: Введение в формат JSON** + +### **Цель урока**: Понять, что такое JSON и научиться отправлять данные в этом формате. + +### **Краткая теория**: +- **JSON (JavaScript Object Notation)** — популярный формат для обмена данными; +- у JSON есть строгий набор правил: + - Все ключи в двойных кавычках + - Значения: строки (в кавычках), числа, true/false, null, массивы [], объекты {} +- **Пример JSON**: +```json +{ + "имя": "Иван", + "возраст": 16, + "хобби": ["программирование", "шахматы"], + "студент": true +} +``` + +### **Практическое задание**: +1. Создайте маршрут `GET /api/user/:id` +2. Если `:id` — число, верните JSON с информацией о пользователе: +```javascript +app.get('/api/user/:id', (req, res) => { + const id = req.params.id; + + if (!isNaN(id)) { + // Формируем вручную объект пользователя. + // Пока что просто притворимся, что мы загрузили его из базы данных. + const userData = { + userId: Number(id), + name: "Алексей Петров", + email: "alexey@example.com", + registered: true + }; + + // Отправляем как JSON + res.json(userData); + } else { + // Если id не число - ошибка в JSON формате + res.status(400).json({ + error: "ID должен быть числом", + example: "/api/user/123" + }); + } +}); +``` +3. Протестируйте в браузере: + - `http://localhost:3000/api/user/123` → увидите красиво оформленный JSON + - `http://localhost:3000/api/user/abc` → JSON с ошибкой + +### Обратите внимание +В примере мы возвращаем фальшивые данные. С настоящими динамическими данными (списки/объекты БД) мы поработаем позже. + +--- + +## 🔄 **Урок 12: Калькулятор с JSON-ответами** + +### **Цель урока**: Переделать текстовый калькулятор для возврата JSON. + +### **Задание**: +Измените все 4 операции калькулятора так, чтобы они возвращали данные в JSON-формате. + +### **Формат успешного ответа**: +```json +{ + "success": true, + "operation": "sum", + "arguments": { + "a": 5, + "b": 3 + }, + "result": 8 +} +``` + +### **Формат ответа с ошибкой**: +```json +{ + "success": false, + "error": { + "code": "DIVISION_BY_ZERO", + "message": "Делитель не может быть равен нулю" + } +} +``` + +### **Как изменить код**: + +1. **Заменяем `res.send()` на `res.json()`** +2. **Для успешного ответа** формируем объект: +```javascript +const response = { + success: true, + operation: "sum", // или "subtract", "multiply", "divide" + arguments: { + a: a, + b: b + }, + result: a + b // здесь ваша операция +}; +res.json(response); +``` + +3. **Для ошибок**: +```javascript +res.status(400).json({ + success: false, + error: { + code: "INVALID_NUMBERS", // или "DIVISION_BY_ZERO" + message: "Оба параметра должны быть числами" + } +}); +``` + +### **Примеры кодов ошибок**: +- `"INVALID_NUMBERS"` — когда параметры не числа +- `"DIVISION_BY_ZERO"` — когда делим на ноль