JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Route Handlers: структура ...

Route Handlers: структура app/api/route.ts в Next.js 15

Модуль 4: Node.js, Next.js и Angular
12 уровень , 0 лекция
Открыта

1. Введение

Если вы когда-нибудь работали с REST API или слышали про backend, то знаете: иногда нужно не только показывать пользователю красивые странички, но и отдавать данные в формате JSON, принимать формы, делать обработку на сервере. В Next.js 15 это делается через Route Handlers – специальные серверные файлы, которые живут прямо внутри папки app/.

Зачем это нужно?

  • Хочется быстро сделать API для фронтенда, не поднимая отдельный Express или Fastify.
  • Нужно обрабатывать запросы из fetch/axios прямо в том же проекте, где живёт ваш сайт.
  • Хотите реализовать логику для форм, обработку загрузки файлов, отправку писем, работу с базой данных и т.д.

Route Handlers — это ваш «мини-бэкенд» внутри Next.js. Не нужно отдельного сервера, всё работает из коробки!

Где живут Route Handlers: структура папок

Всё крутится вокруг папки app/. Для создания API-эндпоинта нужно просто создать папку (например, api) и внутри неё файл с именем route.ts (или route.js).


app/
  api/
    route.ts
  page.tsx
  layout.tsx
Пример структуры папок с Route Handler
  • app/api/route.ts — это и есть ваш API-эндпоинт по адресу /api.
  • Можно делать вложенные папки:
    
    app/api/users/route.ts          → /api/users
    app/api/products/route.ts       → /api/products
    app/api/blog/comments/route.ts  → /api/blog/comments
    

Важно:
В отличие от Page Router (где были папки pages/api/...), в App Router все API-эндпоинты живут в app/ и всегда называются route.ts (или .js).

2. Сигнатура Route Handler: как выглядит базовый файл

Route Handler — это просто экспорт одной или нескольких функций, которые обрабатывают HTTP-методы: GET, POST, PUT, DELETE и т.д.

Минимальный пример:


// app/api/route.ts

export async function GET(request: Request) {
  return new Response('Hello from API!', {
    status: 200,
  });
}
  • Функция называется точно как HTTP-метод (заглавными буквами): GET, POST, PUT, DELETE и т.д.
  • Получает объект Request (стандартный Web API Request, как в fetch).
  • Возвращает объект Response (тоже стандартный Web API Response).
  • Можно экспортировать несколько функций — для разных методов.

Пример с несколькими методами:


// app/api/route.ts

export async function GET(request: Request) {
  return new Response('GET: Hello!');
}

export async function POST(request: Request) {
  return new Response('POST: Data received!');
}

Теперь, если отправить GET-запрос на /api — сработает первая функция, если POST — вторая.

3. Как обращаться к Route Handler из браузера или fetch

GET-запрос:
Просто откройте /api в браузере — увидите "Hello from API!".

POST-запрос:
Можно отправить через fetch, curl, Postman и т.д.

Пример с fetch:


fetch('/api', { method: 'POST' })
  .then(res => res.text())
  .then(console.log); // "POST: Data received!"

4. Работа с Request и Response

Объект Request

Это стандартный объект, как в fetch:

  • request.method — строка с методом (GET, POST и т.д.)
  • request.url — полный URL запроса
  • request.headers — заголовки запроса
  • request.json(), request.text(), request.formData() — методы для чтения тела запроса (для POST/PUT и др.)

Пример: чтение query-параметров


export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const name = searchParams.get('name') ?? 'Гость';
  return new Response(`Привет, ${name}!`);
}

Теперь /api?name=Вася вернёт "Привет, Вася!".

Объект Response

new Response(body, options) — создаёт ответ.

  • body — строка или объект (можно сериализовать через JSON.stringify).
  • options — объект с параметрами: status, headers и т.д.

Пример: отдаём JSON


export async function GET(request: Request) {
  const data = { message: 'Hello, JSON!' };
  return new Response(JSON.stringify(data), {
    status: 200,
    headers: { 'Content-Type': 'application/json' },
  });
}

5. Route Handlers и поддержка разных HTTP-методов

Route Handler может экспортировать сразу несколько функций для разных методов:


export async function GET(request: Request) { ... }
export async function POST(request: Request) { ... }
export async function PUT(request: Request) { ... }
export async function DELETE(request: Request) { ... }

Если отправить запрос с методом, для которого нет обработчика — будет 405 Method Not Allowed.

Пример:


export async function GET(request: Request) {
  return new Response('Только GET!');
}

export async function POST(request: Request) {
  return new Response('Только POST!');
}

6. Пример: создаём простой API для списка задач

Давайте сделаем мини-API для задач (todo-list), чтобы практиковаться.

Шаг 1. Создаём файл

app/api/todos/route.ts

Шаг 2. Пишем код


// app/api/todos/route.ts

let todos = [
  { id: 1, text: 'Купить хлеб', done: false },
  { id: 2, text: 'Выучить Next.js', done: false },
];

// GET /api/todos — получить список задач
export async function GET(request: Request) {
  return new Response(JSON.stringify(todos), {
    headers: { 'Content-Type': 'application/json' },
  });
}

// POST /api/todos — добавить задачу
export async function POST(request: Request) {
  const body = await request.json();
  const newTodo = {
    id: Date.now(),
    text: body.text || '',
    done: false,
  };
  todos.push(newTodo);
  return new Response(JSON.stringify(newTodo), {
    status: 201,
    headers: { 'Content-Type': 'application/json' },
  });
}

Шаг 3. Протестируйте!

  • GET-запрос на /api/todos вернёт весь список задач.
  • POST-запрос с телом { "text": "Сделать домашку" } добавит задачу.

Внимание:
Всё хранится в памяти, при перезапуске сервера данные исчезнут. Для реального приложения нужен бы был база данных, но для практики этого достаточно.

7. Полезные нюансы

Особенности и ограничения Route Handlers

  • Работают только на сервере. В Route Handler нельзя использовать браузерные API (document, window и т.д.).
  • Нет доступа к React-компонентам. Это не страница, а серверная функция.
  • Можно использовать любые npm-пакеты, Node.js API, обращаться к базе данных, файлам и т.д.
  • Можно возвращать любые HTTP-статусы и заголовки.
  • Файл всегда называется route.ts (или .js) — не index.ts, не api.ts, не handler.ts!

Структура вложенных и параметрических маршрутов

Вложенные маршруты

Можно создавать подпапки:


app/api/users/route.ts          → /api/users
app/api/users/profile/route.ts  → /api/users/profile

Динамические сегменты

Можно делать динамические сегменты с помощью квадратных скобок:


app/api/users/[id]/route.ts → /api/users/123

Пример:


// app/api/users/[id]/route.ts

export async function GET(request: Request, { params }) {
  const { id } = params;
  // Получить пользователя по id
  return new Response(`Пользователь #${id}`);
}

Внимание: Второй аргумент — объект с params (в последних версиях Next.js). Если вы не видите params — обновите Next.js или проверьте документацию.

Работа с NextResponse и NextRequest

Next.js предоставляет свои расширенные версии стандартных объектов: NextRequest и NextResponse. Они дают дополнительные удобства (например, работу с cookies, headers, редиректы).


import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ hello: 'world' });
}
  • NextResponse.json(obj) — автоматически сериализует объект в JSON и выставляет правильный Content-Type.
  • Можно легко делать редиректы, устанавливать cookies и т.д.

Рекомендуется использовать NextResponse для JSON-ответов — это проще и короче.

8. Типичные ошибки при работе с Route Handlers

Ошибка №1: забыли назвать файл route.ts
Если назвать файл handler.ts, index.ts или просто api.ts, Next.js не увидит ваш эндпоинт. Только route.ts (или .js).

Ошибка №2: забыли экспортировать функцию с правильным именем
Функция должна называться точно как HTTP-метод — GET, POST (в верхнем регистре!). Если написать get или post, обработчик не сработает.

Ошибка №3: неверная работа с телом запроса
В POST/PUT-запросах тело читается асинхронно:

const data = await request.json();
Если забыть await, получите Promise вместо данных.

Ошибка №4: не выставили Content-Type
Если возвращаете JSON, обязательно укажите

headers: { 'Content-Type': 'application/json' }
Или используйте NextResponse.json() — он делает это автоматически.

Ошибка №5: забыли обработать разные HTTP-методы
Если не экспортировать функцию для нужного метода, Next.js вернёт 405 (Method Not Allowed).

Ошибка №6: пытаетесь использовать браузерные API
В Route Handler нельзя обращаться к window, document и т.д. — это серверный код!

Ошибка №7: не обрабатываете ошибки
Если ваш код может выбросить ошибку (например, при парсинге JSON), используйте try/catch и возвращайте корректный статус и сообщение.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ