JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Формирование ответа: NextR...

Формирование ответа: NextResponse.json(), NextResponse.next()

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

1. NextResponse.json(): возвращаем JSON-ответ

NextResponse — это специальный класс, который расширяет стандартный API Response и добавляет удобные методы для работы с ответами в Next.js. Его цель — сделать формирование ответа простым, безопасным и совместимым со всеми особенностями Next.js (например, с middleware, SSR, кешированием и т.д.).

В Route Handlers (файлы app/api/route.ts или app/api/route.js) вы обычно возвращаете объект типа Response или NextResponse. Если вы возвращаете просто строку, Next.js сам обернёт её в Response. Но если вы хотите контролировать формат, заголовки, статус-код или прокидывать запрос дальше, используйте NextResponse.

Синтаксис

import { NextResponse } from 'next/server';

return NextResponse.json(data, options?);
  • data — любой сериализуемый в JSON объект (обычно это объект или массив).
  • options (необязательно) — объект с дополнительными параметрами (например, статус-код, заголовки).

Простой пример

Допустим, у нас есть API-эндпоинт, который возвращает список задач:

// app/api/todos/route.js
import { NextResponse } from 'next/server';

export async function GET(request) {
  const todos = [
    { id: 1, title: 'Купить хлеб', completed: false },
    { id: 2, title: 'Выучить Next.js', completed: true },
  ];
  return NextResponse.json(todos);
}

Когда клиент отправляет GET-запрос на /api/todos, он получит такой JSON:

[
  { "id": 1, "title": "Купить хлеб", "completed": false },
  { "id": 2, "title": "Выучить Next.js", "completed": true }
]

Автоматические заголовки

NextResponse.json() сам выставляет необходимые заголовки:

  • Content-Type: application/json; charset=utf-8
  • Корректно сериализует данные

Добавление статус-кода

По умолчанию статус-код будет 200 OK. Если нужно другой статус, используйте второй аргумент:

return NextResponse.json(
  { error: 'Not found' },
  { status: 404 }
);

Добавление заголовков

return NextResponse.json(
  { message: 'Created' },
  {
    status: 201,
    headers: {
      'X-Custom-Header': 'Hello!',
    },
  }
);

Пример: создание задачи (POST)

// app/api/todos/route.js
import { NextResponse } from 'next/server';

export async function POST(request) {
  const body = await request.json();
  // Здесь обычно добавление в БД, но мы просто возвращаем то, что получили
  return NextResponse.json(
    { id: Date.now(), ...body },
    { status: 201 }
  );
}

2. NextResponse.next(): прокидываем запрос дальше

Где применяется?

  • В middleware (например, middleware.ts)
  • В сложных сценариях, когда нужно пропустить запрос дальше по цепочке

Пример: middleware, который логирует запросы

// middleware.ts
import { NextResponse } from 'next/server';

export function middleware(request) {
  console.log('Запрос на:', request.nextUrl.pathname);
  // Передаём запрос дальше (к следующему обработчику)
  return NextResponse.next();
}

Если вы вернёте NextResponse.next(), Next.js продолжит обработку запроса (например, дойдёт до Route Handler или страницы).

Важно! В Route Handlers (файлы в app/api/route.js) NextResponse.next() обычно не используют, потому что там вы должны вернуть финальный ответ. Но если вдруг вы строите кастомные цепочки обработки (например, через middleware), этот метод вам пригодится.

3. Практические примеры: полноценный API-эндпоинт

// app/api/todos/route.js
import { NextResponse } from 'next/server';

// Имитация базы данных в памяти (для примера)
const todos = [
  { id: 1, title: 'Погладить кота', completed: false },
  { id: 2, title: 'Сделать домашку', completed: false },
];

// GET — получить все задачи
export async function GET(request) {
  return NextResponse.json(todos);
}

// POST — добавить новую задачу
export async function POST(request) {
  const body = await request.json();
  const newTodo = {
    id: todos.length + 1,
    title: body.title || 'Без названия',
    completed: false,
  };
  todos.push(newTodo);
  return NextResponse.json(newTodo, { status: 201 });
}

Пояснения:
Для GET мы просто возвращаем массив задач.
Для POST разбираем тело запроса, создаём новую задачу, добавляем в массив и возвращаем её клиенту с кодом 201 (Created).

4. Как формировать разные типы ответов

Ошибка (например, задача не найдена)

export async function GET(request) {
  // ... поиск задачи
  if (!todo) {
    return NextResponse.json(
      { error: 'Задача не найдена' },
      { status: 404 }
    );
  }
  return NextResponse.json(todo);
}

Успех без данных (например, удаление задачи)

export async function DELETE(request) {
  // ... удалили задачу
  return NextResponse.json(
    { message: 'Задача удалена' },
    { status: 200 }
  );
}

Кастомные заголовки

return NextResponse.json(
  { data: 'OK' },
  { headers: { 'X-API-Version': '1.0.0' } }
);

5. Сравнение NextResponse.json() и обычного Response

Можно возвращать и стандартный Response:

return new Response(JSON.stringify(data), {
  status: 200,
  headers: { 'Content-Type': 'application/json' },
});

Но!

  • NextResponse.json() делает всё это за вас автоматически.
  • Гарантирует совместимость с Next.js (например, для middleware, кеширования, Edge Runtime).
  • Код лаконичнее и меньше шансов ошибиться с заголовками.

Совет: Используйте NextResponse.json() для JSON-ответов — это best practice.

6. Типичные ошибки при формировании ответа

Ошибка №1: забыли выставить статус-код
Если не указать статус явно, по умолчанию будет 200. Иногда забывают выставить 201 для создания или 404 для ошибки, и клиент не понимает, что произошло.

Ошибка №2: возвращаете не сериализуемый объект
NextResponse.json() не сможет сериализовать, например, функцию, класс или объект с circular reference. Всегда возвращайте только простые объекты, массивы, числа, строки, булевы значения.

Ошибка №3: не тот Content-Type
Если используете обычный Response, можно забыть указать Content-Type: application/json, и клиент не сможет корректно обработать ответ. NextResponse.json() делает это за вас.

Ошибка №4: используете NextResponse.next() вместо финального ответа
В Route Handler всегда нужно возвращать финальный ответ (NextResponse.json(), строку, Response и т.д.), а не NextResponse.next(). Последний нужен только для middleware.

Ошибка №5: не await-ите request.json()
Если забыть await при чтении тела запроса, получите Promise вместо данных, что приведёт к ошибкам.

// Ошибка:
const body = request.json(); // body — Promise!

// Правильно:
const body = await request.json();
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ