Пошук уроків, статей та іншого контенту
Використайте NextResponse для JSON-відповідей, перенаправлень, статусів і керування заголовками.
NextResponseNextResponse — це клас Next.js для формування відповідей у Route Handlers та Middleware.
За допомогою нього можна:
повернути JSON;
встановити HTTP-статус;
додати або змінити заголовки;
перенаправити користувача на іншу сторінку.
Імпортувати NextResponse потрібно з next/server:
import { NextResponse } from 'next/server';Відповідь, створену через NextResponse, потрібно повернути з обробника за допомогою return.
Найчастіше NextResponse використовується для повернення JSON з API-маршрутів.
Наприклад, файл:
app/api/products/route.jsможе містити такий обробник:
import { NextResponse } from 'next/server';
export async function GET() {
const products = [
{ id: 1, name: 'Keyboard', price: 1200 },
{ id: 2, name: 'Mouse', price: 800 },
];
return NextResponse.json(products);
}Після запиту GET /api/products клієнт отримає:
[
{ "id": 1, "name": "Keyboard", "price": 1200 },
{ "id": 2, "name": "Mouse", "price": 800 }
]Метод NextResponse.json() автоматично:
перетворює JavaScript-значення на JSON;
встановлює заголовок Content-Type: application/json;
створює об'єкт відповіді.
Також можна повернути JSON-об'єкт:
import { NextResponse } from 'next/server';
export async function GET() {
return NextResponse.json({
message: 'Products loaded successfully',
});
}Другий аргумент NextResponse.json() — це параметри відповіді. Через нього можна встановити статус.
import { NextResponse } from 'next/server';
export async function POST() {
const product = {
id: 3,
name: 'Monitor',
price: 9000,
};
return NextResponse.json(product, {
status: 201,
});
}Статус 201 Created означає, що новий ресурс було створено.
Для помилки можна використати статус 400:
import { NextResponse } from 'next/server';
export async function POST() {
return NextResponse.json(
{
error: 'Product name is required',
},
{
status: 400,
}
);
}Поширені статуси:
200 — успішна відповідь;
201 — ресурс створено;
400 — некоректний запит;
401 — користувач не автентифікований;
403 — доступ заборонено;
404 — ресурс не знайдено;
500 — помилка на сервері.
Статус потрібно обирати відповідно до результату операції, а не завжди повертати 200.
У Route Handler можна отримати об'єкт запиту як параметр функції.
Для JSON із тіла запиту використовується request.json():
import { NextResponse } from 'next/server';
export async function POST(request) {
const body = await request.json();
if (!body.name || !body.price) {
return NextResponse.json(
{
error: 'Name and price are required',
},
{
status: 400,
}
);
}
const product = {
id: 1,
name: body.name,
price: body.price,
};
return NextResponse.json(product, {
status: 201,
});
}Оскільки request.json() повертає Promise, перед викликом потрібно використати await.
Приклад запиту до такого обробника:
const response = await fetch('/api/products', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Monitor',
price: 9000,
}),
});
const data = await response.json();Параметри після знака ? можна прочитати через request.url.
import { NextResponse } from 'next/server';
export async function GET(request) {
const url = new URL(request.url);
const category = url.searchParams.get('category');
return NextResponse.json({
category,
});
}Для запиту:
/api/products?category=electronicsвідповідь буде такою:
{
"category": "electronics"
}Якщо параметр відсутній, searchParams.get() поверне null.
Для перенаправлення використовується NextResponse.redirect().
import { NextResponse } from 'next/server';
export async function GET(request) {
const isAuthenticated = false;
if (!isAuthenticated) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.json({
message: 'Private data',
});
}request.url використовується як основа для створення повного URL.
Можна явно вказати статус перенаправлення:
import { NextResponse } from 'next/server';
export async function GET(request) {
return NextResponse.redirect(
new URL('/products', request.url),
302
);
}Перенаправлення також потрібно повернути через return. Якщо не повернути його з обробника, сформована відповідь не буде використана.
Заголовки можна передати під час створення відповіді через поле headers.
import { NextResponse } from 'next/server';
export async function GET() {
return NextResponse.json(
{
message: 'Data loaded',
},
{
status: 200,
headers: {
'Cache-Control': 'no-store',
'X-API-Version': '1',
},
}
);
}У результаті відповідь матиме такі заголовки:
Cache-Control: no-store
X-API-Version: 1Заголовки також можна змінити після створення відповіді:
import { NextResponse } from 'next/server';
export async function GET() {
const response = NextResponse.json({
message: 'Data loaded',
});
response.headers.set('X-API-Version', '1');
response.headers.set('Cache-Control', 'no-store');
return response;
}Метод headers.set() встановлює значення заголовка або замінює його, якщо такий заголовок уже існує.
Нижче наведено приклад файлу app/api/products/route.js, який демонструє JSON-відповіді, статуси, заголовки та перенаправлення:
import { NextResponse } from 'next/server';
const products = [
{ id: 1, name: 'Keyboard', price: 1200 },
{ id: 2, name: 'Mouse', price: 800 },
];
export async function GET(request) {
const url = new URL(request.url);
const productId = url.searchParams.get('id');
if (productId) {
const product = products.find(
(item) => item.id === Number(productId)
);
if (!product) {
return NextResponse.json(
{
error: 'Product not found',
},
{
status: 404,
}
);
}
return NextResponse.json(product, {
headers: {
'Cache-Control': 'no-store',
},
});
}
return NextResponse.json(products, {
headers: {
'Cache-Control': 'no-store',
'X-API-Version': '1',
},
});
}
export async function POST(request) {
const body = await request.json();
if (!body.name || typeof body.price !== 'number') {
return NextResponse.json(
{
error: 'Name and numeric price are required',
},
{
status: 400,
}
);
}
const product = {
id: products.length + 1,
name: body.name,
price: body.price,
};
products.push(product);
return NextResponse.json(product, {
status: 201,
headers: {
'X-API-Version': '1',
},
});
}Цей обробник підтримує:
GET /api/products — повертає всі товари;
GET /api/products?id=1 — повертає один товар;
GET /api/products?id=999 — повертає помилку зі статусом 404;
POST /api/products — створює товар;
некоректний POST — повертає помилку зі статусом 400.
returnНеправильно:
import { NextResponse } from 'next/server';
export async function GET() {
NextResponse.json({ message: 'Hello' });
}Правильно:
import { NextResponse } from 'next/server';
export async function GET() {
return NextResponse.json({ message: 'Hello' });
}Не варто повертати помилку зі статусом 200:
return NextResponse.json(
{ error: 'Invalid data' },
{ status: 200 }
);Краще використати відповідний статус:
return NextResponse.json(
{ error: 'Invalid data' },
{ status: 400 }
);await для request.json()Неправильно:
const body = request.json();У такому випадку body буде Promise, а не отриманими даними.
Правильно:
const body = await request.json();Content-Type під час надсилання JSONЯкщо клієнт надсилає JSON, потрібно вказати його тип:
await fetch('/api/products', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Monitor',
price: 9000,
}),
});NextResponse.json() створює JSON-відповідь.
Статус задається другим аргументом, наприклад { status: 201 }.
NextResponse.redirect() перенаправляє запит на іншу адресу.
Заголовки можна передати через headers або змінити методом response.headers.set().
Кожну створену відповідь потрібно повернути через return.
Дані з JSON-тіла запиту отримуються через await request.json().