Пошук уроків, статей та іншого контенту
Створіть динамічні API-маршрути та отримуйте параметри шляху в Route Handler.
У Next.js Route Handler можна створити в динамічному сегменті маршруту. Такий сегмент позначається квадратними дужками:
app/api/products/[id]/route.tsСегмент [id] означає, що замість нього в URL може бути будь-яке значення:
/api/products/1
/api/products/42
/api/products/abcЗначення динамічного сегмента передається до Route Handler через другий аргумент функції.
Приклад структури файлів:
app/
└── api/
└── products/
└── [id]/
└── route.tsФайл route.ts обробляє запити до адреси:
/api/products/:idде :id — це значення сегмента [id].
Наприклад:
| URL | Значення id | |---|---| | /api/products/1 | "1" | | /api/products/phone | "phone" | | /api/products/abc-123 | "abc-123" |
Параметри шляху завжди надходять як рядки. Якщо параметр має бути числом, його потрібно перетворити та перевірити самостійно.
У сучасних версіях Next.js параметри маршруту в Route Handler представлені як Promise. Тому їх потрібно отримати за допомогою await:
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
return Response.json({ id });
}Для запиту:
GET /api/products/42відповідь буде такою:
{
"id": "42"
}Назва параметра в типі має збігатися з назвою динамічної папки. Для папки [id] використовується params.id, а для папки [slug] — params.slug.
Створимо Route Handler, який шукає товар за ідентифікатором.
Файл app/api/products/[id]/route.ts:
type Product = {
id: number;
name: string;
price: number;
};
const products: Product[] = [
{
id: 1,
name: "Механічна клавіатура",
price: 3200,
},
{
id: 2,
name: "Бездротова миша",
price: 1800,
},
{
id: 3,
name: "USB-C хаб",
price: 1400,
},
];
export async function GET(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const productId = Number(id);
if (!Number.isInteger(productId) || productId <= 0) {
return Response.json(
{ error: "Ідентифікатор товару має бути додатним цілим числом" },
{ status: 400 }
);
}
const product = products.find((item) => item.id === productId);
if (!product) {
return Response.json(
{ error: "Товар не знайдено" },
{ status: 404 }
);
}
return Response.json(product);
}Тепер запит:
GET /api/products/2поверне:
{
"id": 2,
"name": "Бездротова миша",
"price": 1800
}А запит до неіснуючого товару:
GET /api/products/99поверне статус 404:
{
"error": "Товар не знайдено"
}Якщо передати некоректний ідентифікатор:
GET /api/products/keyboardсервер поверне статус 400:
{
"error": "Ідентифікатор товару має бути додатним цілим числом"
}Маршрут може містити більше одного динамічного сегмента. Наприклад:
app/api/users/[userId]/orders/[orderId]/route.tsДля такого маршруту тип параметрів буде містити обидва значення:
export async function GET(
_request: Request,
{
params,
}: {
params: Promise<{
userId: string;
orderId: string;
}>;
}
) {
const { userId, orderId } = await params;
return Response.json({
userId,
orderId,
});
}Запит:
/api/users/10/orders/25дасть такі параметри:
{
"userId": "10",
"orderId": "25"
}Кожен параметр відповідає своїй динамічній папці.
Параметр шляху і query-параметр — це різні частини URL.
Для URL:
/api/products/2?currency=eurid — параметр шляху зі значенням "2";
currency — query-параметр зі значенням "eur".
Параметр шляху отримують через params, а query-параметри — через request.url:
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const url = new URL(request.url);
const currency = url.searchParams.get("currency");
return Response.json({
id,
currency,
});
}Для запиту:
/api/products/2?currency=eurрезультат буде таким:
{
"id": "2",
"currency": "eur"
}Той самий динамічний параметр можна використовувати в обробниках PATCH або DELETE.
Наприклад, Route Handler може видаляти товар за його ідентифікатором:
type Product = {
id: number;
name: string;
price: number;
};
const products: Product[] = [
{
id: 1,
name: "Механічна клавіатура",
price: 3200,
},
{
id: 2,
name: "Бездротова миша",
price: 1800,
},
];
export async function DELETE(
_request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const productId = Number(id);
const productIndex = products.findIndex((product) => product.id === productId);
if (productIndex === -1) {
return Response.json(
{ error: "Товар не знайдено" },
{ status: 404 }
);
}
const [deletedProduct] = products.splice(productIndex, 1);
return Response.json({
message: "Товар видалено",
product: deletedProduct,
});
}Обробник доступний за тією самою адресою:
DELETE /api/products/2Метод запиту визначає, яку експортовану функцію використає Next.js:
GET — GET;
POST — POST;
PATCH — PATCH;
DELETE — DELETE.
Після запуску застосунку в режимі розробки:
npm run devможна виконати запит за допомогою curl:
curl http://localhost:3000/api/products/1Для перевірки помилки:
curl -i http://localhost:3000/api/products/999Параметр -i показує також HTTP-статус відповіді.
await paramsУ сучасних версіях Next.js параметри потрібно отримати асинхронно:
const { id } = await params;Неправильний варіант:
const { id } = params;Для структури:
app/api/products/[id]/route.tsпотрібно використовувати params.id.
Неправильно:
const { productId } = await params;Якщо потрібна назва productId, папка має називатися [productId].
Навіть якщо URL має вигляд /api/products/42, значення id буде рядком:
typeof id; // "string"Перед роботою з числовим ідентифікатором використовуйте перетворення та валідацію:
const productId = Number(id);
if (!Number.isInteger(productId)) {
return Response.json(
{ error: "Некоректний ідентифікатор" },
{ status: 400 }
);
}Якщо повернути помилку без параметра status, відповідь матиме статус 200, хоча операція завершилася невдало:
return Response.json({ error: "Не знайдено" });Правильний варіант:
return Response.json(
{ error: "Не знайдено" },
{ status: 404 }
);route.tsRoute Handler повинен називатися саме route.ts або route.js і знаходитися всередині директорії маршруту:
app/api/products/[id]/route.tsФайл із назвою handler.ts не буде автоматично розпізнаний як Route Handler.
Динамічний сегмент маршруту створюється папкою на кшталт [id].
Файл app/api/products/[id]/route.ts обробляє запити до /api/products/:id.
Параметри шляху доступні в другому аргументі Route Handler.
У сучасних версіях Next.js параметри потрібно отримувати через await params.
Значення параметрів надходять як рядки, тому числові значення потрібно перетворювати та перевіряти.
Для відсутнього ресурсу слід повертати статус 404, а для некоректного параметра — 400.
Один динамічний маршрут може мати окремі обробники для різних HTTP-методів.