Express связывает HTTP-метод и путь с функцией, которая читает запрос и формирует JSON-ответ. Соберём API задач с GET /tasks и POST /tasks, проверим пустой title и увидим разницу между статусами 200, 201 и 400. База пока не нужна: данные живут в массиве, чтобы маршрут запроса был виден целиком.
Новичок часто видит route, middleware и status как отдельные термины. Один сервер показывает их в реальном порядке от входящего запроса до ответа. В этой статье вы соберёте локальный REST API с двумя маршрутами. Финальный результат можно проверить без догадок: curl получает исходный список, POST создаёт задачу с новым id, а пустой title возвращает JSON-ошибку и код 400.
Читает список и не меняет состояние сервера.
Принимает JSON, проверяет title и добавляет новую задачу.
Возвращает статус, заголовок Content-Type и сериализованное тело.
Как HTTP-запрос попадает в Express
Клиент отправляет метод, URL, заголовки и тело. Express вызывает express.json до маршрутов, затем выбирает app.get или app.post по методу и path. Handler читает req.body, меняет массив и завершает запрос через res.json или res.status(...).json. Для Express API держите этапы раздельно: ввод, проверка, основное действие и вывод. Такой маршрут позволяет остановиться в конкретной точке, увидеть фактические данные и исправить одну причину вместо случайной перестановки строк.
| Этап | Действие | Проверяемый результат |
|---|---|---|
| Приём | Node.js получает HTTP-запрос | Есть method и URL |
| Middleware | express.json разбирает body | req.body является объектом |
| Route | Express сопоставляет метод и path | Выбран один handler |
| Ответ | Handler задаёт status и JSON | Клиент получает завершённый response |
Маршрут является парой метод + путь, поэтому GET /tasks и POST /tasks могут существовать одновременно. У Express API каждый этап оставляет наблюдаемый след, поэтому следующий шаг начинается только после проверки предыдущего.

От входных данных до видимого результата. Метод и путь выбирают ровно один handler
Пишем GET и POST маршруты
Создайте каталог, выполните npm init -y и npm install express. Добавьте в package.json поле "type": "module", сохраните server.js и запустите node server.js. Для автоматического перезапуска можно использовать node --watch server.js. Проверяйте запросы во втором терминале через curl.
import express from "express";
const app = express();
app.use(express.json({ limit: "20kb" }));
const tasks = [
{ id: 1, title: "Read Express docs", done: false },
];
app.get("/tasks", (request, response) => {
response.json({ items: tasks, count: tasks.length });
});
app.post("/tasks", (request, response) => {
const title = request.body?.title;
if (typeof title !== "string" || title.trim().length < 2) {
return response.status(400).json({
error: "title must contain at least 2 characters",
});
}
const task = {
id: tasks.at(-1)?.id + 1 || 1,
title: title.trim(),
done: false,
};
tasks.push(task);
return response.status(201).json(task);
});
app.use((request, response) => {
response.status(404).json({ error: "route not found" });
});
app.listen(3000, () => {
console.log("API: http://localhost:3000");
});- GET /tasks отвечает кодом 200 и массивом items.
- POST /tasks с title отвечает 201 и созданным объектом.
- Пустой title отвечает 400 без изменения массива.
- Неизвестный путь отвечает JSON с кодом 404.
return перед error-response не обязателен для Express, но он явно останавливает handler и защищает от второго ответа. Пример Express API специально ограничен одним пользовательским сценарием, чтобы назначение каждой строки оставалось видимым.

Что отличает устойчивый проект от случайного запуска. Статус является частью ответа
Зачем нужны middleware и коды ответа
express.json является middleware: он выполняется до подходящего маршрута и вызывает next после разбора тела. Если Content-Type не application/json, req.body может остаться undefined. res.json сериализует объект и задаёт тип ответа. Код 201 сообщает, что ресурс создан, а 400 означает ошибку входных данных. Массив существует только в памяти процесса, поэтому перезапуск сервера удаляет новые задачи. Это нормально для лаборатории, но не для настоящего хранения.
| Часть | За что отвечает | Что проверить |
|---|---|---|
| app.use | Подключает middleware | Парсер стоит до маршрутов |
| app.get | Обрабатывает чтение | Не изменяет tasks |
| app.post | Создаёт ресурс | Проверяет body до push |
| res.status | Задаёт код HTTP | 201 и 400 различаются |
| 404 handler | Ловит неизвестные пути | Стоит после маршрутов |
Query string не является частью route path: /tasks?done=true всё равно попадает в /tasks, а параметр читается через req.query. Для /tasks/:id используется req.params. Асинхронная база добавит await и обработку ошибок, но не меняет контракт маршрута. Не возвращайте stack trace клиенту. В Express 5 отклонённый Promise из async-handler передаётся обработчику ошибок, однако в учебном сервере полезно сначала увидеть синхронный путь. Ограничение body защищает лабораторию от случайно огромного JSON, но не заменяет аутентификацию и rate limit.
Проверяем API через curl и неверный JSON
Запустите сервер и выполните GET. Создайте задачу через curl -X POST http://localhost:3000/tasks -H "Content-Type: application/json" -d "{"title":"Write tests"}". Повторите GET. Затем отправьте пустую строку, число и сломанный JSON. Добавьте PATCH /tasks/:id, который меняет done, но сначала проверяет числовой id и наличие задачи. Верните 404, если id не найден. После этого вынесите проверку title в функцию и протестируйте её отдельно.
- Получите начальный список через GET.
- Создайте задачу и проверьте статус 201.
- Отправьте пустой title и получите 400.
- Откройте неизвестный путь и получите 404.
- Добавьте PATCH для поля done.
- Перезапустите сервер и объясните потерю данных.
- GET не меняет массив.
- POST валидирует JSON.
- Коды ответа различаются.
- 404 возвращается в одном формате.
Рабочий API определяется не количеством маршрутов, а предсказуемым контрактом для успеха и ошибки. После этой проверки измените одно правило Express API и заранее запишите ожидаемый результат. Так копирование превращается в понимание.

Четыре проверки перед следующим шагом. Ошибки проверяются так же, как успех
Что добавить перед настоящим продом
Перед продом замените массив базой, добавьте схему валидации, единый error-handler, журнал запросов и тесты. Аутентификацию подключайте до приватных маршрутов. CORS нужен только когда браузерный клиент находится на другом origin, он не защищает сервер от curl. Настройте переменную PORT вместо жёсткого 3000 и корректное завершение процесса. Документируйте пример request и response для каждого статуса, чтобы фронтенд не угадывал форму ошибки.
Как изучить тему в Кодике
Повторите объекты, массивы, функции и условия JavaScript, затем наложите на них HTTP-методы. В Кодике сначала восстановите чистую логику без фреймворка, затем верните библиотеку и интерфейс Express API.
| Шаг | Что разобрать | Мини-проверка |
|---|---|---|
| 1 | Объекты и JSON | Сериализовать одну task |
| 2 | Функции | Написать handler из двух аргументов |
| 3 | Массивы | Добавить task и посчитать count |
| 4 | Условия | Отклонить пустой title |
| 5 | HTTP | Развести 200, 201, 400 и 404 |
Если форма данных понятна без Express, маршрут становится короткой оболочкой вокруг знакомой логики. Финальная проверка для Express API: закрыть статью, объяснить путь данных и добавить одну функцию без копирования готового блока.
req.body не будет разобран для application/json.
Используйте 201 для создания и 400 для неверного ввода.
Строка из пробелов truthy, поэтому применяйте trim и длину.
После перезапуска память очистится, это часть ограничения примера.
Что получится в итоге

Два маршрута возвращают единый JSON-формат, различают успешное чтение, создание, неверные данные и неизвестный адрес.
Что делает express.json?
express.json разбирает JSON-тело запроса и записывает объект в req.body до маршрута.
Чем GET /tasks отличается от POST /tasks?
GET читает список, а POST принимает данные и создаёт новую задачу.
Когда Express API возвращает 201?
Код 201 возвращается после успешного создания нового ресурса.
Как понять, что учебный проект Express API действительно работает?
Проверьте основной сценарий Express API, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.
Можно ли начать с готового кода Express API из статьи?
Да. Сначала добейтесь результата Express API, затем измените одно правило и восстановите ключевой файл без копирования.
JavaScript закрепите в курсе JavaScript, а серверные принципы в профессии Backend. Клиентский запрос разберите в статье про Fetch API.
Сравните обычные маршруты с WebSocket-чатом и подключение данных с Supabase Auth.