В приложении заметок их стали сотни — список больше нельзя отдавать целиком. Строим GET-эндпоинт с поиском, тегами, сортировкой и пагинацией через query-параметры.
Ты — бэкендер в команде приложения «Блокнот». Утро начинается с сообщения от фронтендера:
«У активного пользователя уже 400+ заметок. Мы грузим их все одним запросом, и список собирается секунды три. Нужен нормальный GET-эндпоинт: поиск, фильтр по тегу, сортировка и страницы. Я на фронте всё нарисовал — дело за тобой».
Заводить четыре разных маршрута не нужно. Всё это — один GET /api/notes, который меняет поведение через query-параметры.
/api/notes?search=api&tag=учёба&page=2
│ │ │ │
│ │ │ └─ третья пара ключ=значение
│ │ └─ пары разделяются символом &
│ └─ первая пара: ключ search, значение api
└─ знак ? отделяет путь от параметровExpress разбирает эту строку сам и кладёт результат в req.query:
// GET /api/notes?search=api&tag=учёба&page=2
req.query // → { search: 'api', tag: 'учёба', page: '2' }⚠️ Запомни главное: все значения — строки. Даже page=2 приедет как '2', а не 2. Забудешь превратить в число — получишь '2' + 1 === '21'.
| Параметр | Пример | Что делает |
|---|---|---|
search | ?search=api | подстрока в title или text, без учёта регистра |
tag | ?tag=учёба | только заметки с этим тегом |
sort | ?sort=new / old / title | сначала новые / сначала старые / по алфавиту |
page, limit | ?page=2&limit=5 | страница и её размер |
Все параметры необязательные и комбинируются как угодно: ?search=api&tag=учёба&sort=new&page=1&limit=5 — валидный запрос.
В первых шагах эндпоинт возвращает просто массив заметок:
[ { "id": 3, "title": "Что такое REST API" } ]А на шаге пагинации мы переедем на конверт:
{ "items": [...], "total": 42, "page": 2, "limit": 5 }Так растут настоящие API: сначала простой ответ, потом появляется пагинация — и массива уже мало, нужно поле total. Мы пройдём эту эволюцию руками, чтобы ты видел, зачем каждая часть контракта.
?search= — регистронезависимый?tag= — работает вместе с поиском?sort= — по дате и алфавиту?page=&limit= — конверт с totalGET /api/notes/tags — счётчики для чипов на фронтеСкелет сервера уже знаком тебе по прошлым проектам — дальше наращиваем мясо.
const app = express();
app.use(express.json());
// Хранилище в памяти: 8 заметок (в песочнице они уже будут в коде)
const notes = [
{ id: 1, title: "Идея пет-проекта", text: "Трекер привычек...", tags: ["идеи"], createdAt: "2026-05-14" },
// ...ещё 7 заметок
];
// Шаги 2–4: GET /api/notes → массив (поиск, тег, сортировка)
// Шаг 5: GET /api/notes → конверт { items, total, page, limit }
// Шаг 6: GET /api/notes/tags → [{ tag, count }]
app.listen(3000, () => console.log('✅ http://localhost:3000'));Конвейер обработки запроса — нажми на узел, чтобы увидеть пояснение.
Один эндпоинт, поведение меняют query-параметры. Все они необязательны и комбинируются. Все значения — строки: page=2 приедет как '2'.