Пошук уроків, статей та іншого контенту
Навчіться читати дані запиту й формувати коректні відповіді через Request та Response.
У Next.js API-обробник отримує об’єкт Request і повертає об’єкт Response.
Request містить усе, що клієнт надіслав на сервер:
HTTP-метод;
URL і query-параметри;
заголовки;
тіло запиту.
Response описує відповідь сервера:
дані;
HTTP-статус;
заголовки.
У Next.js з App Router API-обробники створюють у файлі route.js або route.ts. Назва експортованої функції відповідає HTTP-методу:
app/api/tasks/route.jsexport async function GET(request) {
// Обробка GET-запиту
}
export async function POST(request) {
// Обробка POST-запиту
}Якщо обробник уже оголошено як GET або POST, назва функції визначає метод запиту:
export async function GET(request) {
console.log(request.method); // GET
return Response.json({ message: "Успішно" });
}Властивість request.method містить рядок із назвою методу: GET, POST, PUT, DELETE тощо.
Повний URL доступний у request.url. Щоб зручно прочитати query-параметри, створіть об’єкт URL:
export async function GET(request) {
const url = new URL(request.url);
const name = url.searchParams.get("name");
return Response.json({
message: `Привіт, ${name ?? "гість"}!`,
});
}Для запиту:
/api/greeting?name=Оленазначення name буде "Олена".
Якщо параметр відсутній, searchParams.get() повертає null.
Заголовки доступні через request.headers:
export async function GET(request) {
const authorization = request.headers.get("authorization");
const requestId = request.headers.get("x-request-id");
return Response.json({
authorization,
requestId,
});
}Метод headers.get() повертає значення заголовка або null, якщо такого заголовка немає.
Тіло POST-запиту часто містить JSON. Для його читання використовуйте асинхронний метод request.json():
export async function POST(request) {
const data = await request.json();
return Response.json({
received: data,
});
}Клієнт має надіслати коректний JSON, наприклад:
{
"title": "Вивчити Next.js"
}Метод request.json() асинхронний, тому перед ним потрібно використати await. Також тіло запиту не варто читати кілька разів: після виклику request.json() воно вже спожите.
Для JSON зручно використовувати Response.json():
return Response.json({
message: "Дані отримано",
});Такий виклик створює відповідь із JSON-даними та відповідним заголовком Content-Type.
Другий аргумент Response.json() дає змогу вказати статус:
return Response.json(
{ message: "Ресурс створено" },
{ status: 201 }
);Поширені статуси для API:
200 OK — запит успішний;
201 Created — ресурс створено;
400 Bad Request — клієнт надіслав некоректні дані;
404 Not Found — ресурс не знайдено;
500 Internal Server Error — помилка на сервері.
Заголовки відповіді також можна передати другим аргументом:
return Response.json(
{ message: "Запит оброблено" },
{
status: 200,
headers: {
"X-Request-Id": "request-123",
},
}
);Створіть файл:
app/api/tasks/route.jsУ цьому прикладі API:
повертає список завдань через GET;
підтримує query-параметр completed;
читає JSON із POST;
перевіряє вхідні дані;
повертає різні HTTP-статуси.
let tasks = [
{
id: 1,
title: "Вивчити Request",
completed: true,
},
{
id: 2,
title: "Вивчити Response",
completed: false,
},
];
let nextId = 3;
export async function GET(request) {
const url = new URL(request.url);
const completed = url.searchParams.get("completed");
const requestId = request.headers.get("x-request-id");
let result = tasks;
if (completed === "true" || completed === "false") {
const completedValue = completed === "true";
result = tasks.filter((task) => task.completed === completedValue);
}
return Response.json(result, {
status: 200,
headers: {
"X-Request-Id": requestId ?? "not-provided",
},
});
}
export async function POST(request) {
let data;
try {
data = await request.json();
} catch {
return Response.json(
{ error: "Тіло запиту має бути коректним JSON" },
{ status: 400 }
);
}
if (typeof data.title !== "string" || data.title.trim() === "") {
return Response.json(
{ error: "Поле title є обов'язковим" },
{ status: 400 }
);
}
const task = {
id: nextId,
title: data.title.trim(),
completed: data.completed === true,
};
tasks.push(task);
nextId += 1;
return Response.json(task, { status: 201 });
}Запит без фільтра поверне всі завдання:
GET /api/tasksВідповідь:
[
{
"id": 1,
"title": "Вивчити Request",
"completed": true
},
{
"id": 2,
"title": "Вивчити Response",
"completed": false
}
]Щоб отримати лише невиконані завдання:
GET /api/tasks?completed=falseОбробник читає параметр через:
const url = new URL(request.url);
const completed = url.searchParams.get("completed");Запит із коректним тілом:
POST /api/tasks
Content-Type: application/json{
"title": "Написати API-обробник",
"completed": false
}У відповідь сервер поверне статус 201 і створене завдання:
{
"id": 3,
"title": "Написати API-обробник",
"completed": false
}Якщо поле title відсутнє або порожнє, сервер поверне:
{
"error": "Поле title є обов'язковим"
}Статус такої відповіді буде 400.
Виклик request.json() може завершитися помилкою, якщо:
тіло запиту порожнє;
тіло містить некоректний JSON;
клієнт надіслав не ті дані, які очікує API.
Тому для зовнішніх запитів корисно використовувати try...catch:
export async function POST(request) {
try {
const data = await request.json();
return Response.json({
received: data,
});
} catch {
return Response.json(
{ error: "Не вдалося прочитати JSON" },
{ status: 400 }
);
}
}Перевірка формату JSON і перевірка значень полів — це різні перевірки:
request.json() перевіряє, чи можна прочитати JSON;
умови після цього перевіряють, чи відповідають дані вимогам API.
У більшості простих обробників послідовність така:
Прочитати потрібні дані з Request.
Перевірити отримані значення.
Виконати потрібну дію.
Повернути Response із даними та правильним статусом.
Наприклад:
export async function POST(request) {
const data = await request.json();
if (!data.name) {
return Response.json(
{ error: "Поле name є обов'язковим" },
{ status: 400 }
);
}
return Response.json(
{ message: `Користувача ${data.name} створено` },
{ status: 201 }
);
}await перед request.json()Неправильно:
const data = request.json();У змінній data буде Promise, а не вже прочитані дані.
Правильно:
const data = await request.json();Якщо клієнт надіслав пошкоджений JSON, request.json() може викинути помилку. Для API, яке приймає дані від клієнта, обробляйте цю ситуацію через try...catch.
Якщо ресурс створено, краще повернути 201, а не загальний 200. Якщо дані не пройшли перевірку, використовуйте 400.
return Response.json(
{ error: "Некоректні дані" },
{ status: 400 }
);Не варто одразу зберігати значення з Request. Перевірте:
чи існує потрібне поле;
чи має воно правильний тип;
чи не є рядок порожнім;
чи відповідає значення очікуваному формату.
У запиті:
/api/tasks?completed=truecompleted — query-параметр, його читають через request.url.
У запиті з JSON:
{
"title": "Нове завдання"
}title — дані тіла запиту, їх читають через await request.json().
Request містить дані, які клієнт надіслав серверу.
URL читають через request.url і об’єкт URL.
Query-параметри отримують через url.searchParams.get().
Заголовки читають через request.headers.get().
JSON-тіло читають асинхронно через await request.json().
Response.json() формує JSON-відповідь.
HTTP-статус передають у другому аргументі Response.json().
Некоректні дані потрібно відхиляти зі статусом 400.
Успішне створення ресурсу зазвичай повертає статус 201.