Научете как да създавате мощни API крайни точки с Next.js Route Handlers. Ръководството обхваща всичко от основна настройка до напреднали техники, с практически примери и добри практики.
Next.js Route Handlers: Цялостно ръководство за създаване на API крайни точки
Next.js направи революция в начина, по който изграждаме уеб приложения със своите мощни функции като рендиране от страна на сървъра, генериране на статични сайтове и сега, Route Handlers. Route Handlers предоставят гъвкав и ефективен начин за създаване на API крайни точки директно във вашето Next.js приложение. Това ръководство изследва концепцията на Route Handlers, техните предимства и как ефективно да ги използвате за изграждане на стабилни API-та.
Какво представляват Next.js Route Handlers?
Route Handlers са функции, дефинирани в директорията app
на Next.js проект, които обработват входящи HTTP заявки. За разлика от по-стария подход с pages/api
(който използва API Routes), Route Handlers предлагат по-оптимизиран и гъвкав начин за дефиниране на API крайни точки заедно с вашите React компоненти. Те по същество са сървърлес функции, изпълнявани на edge или във вашата избрана сървърна среда.
Мислете за Route Handlers като за бекенд логиката на вашето Next.js приложение, отговорна за обработката на заявки, взаимодействието с бази данни и връщането на отговори.
Предимства на използването на Route Handlers
- Колокация: Route Handlers се намират директно до вашите React компоненти в директорията
app
, което насърчава по-добрата организация и поддръжка на кода. - Поддръжка на TypeScript: Вградената поддръжка на TypeScript осигурява типова безопасност и подобрено преживяване за разработчиците.
- Интеграция на Middleware: Лесно интегриране на middleware за задачи като автентикация, оторизация и валидация на заявки.
- Поддръжка на стрийминг: Route Handlers могат да стриймват данни, което ви позволява да изпращате отговори инкрементално, което е полезно за големи набори от данни или дълготрайни процеси.
- Edge функции: Внедрявайте Route Handlers като Edge функции за отговори с ниска латентност, по-близо до вашите потребители, използвайки глобални CDN мрежи.
- Опростен дизайн на API: Route Handlers предоставят изчистен и интуитивен API за обработка на заявки и отговори.
- Интеграция със Server Actions: Тясната интеграция със Server Actions позволява безпроблемна комуникация между вашите клиентски компоненти и сървърната логика.
Настройка на вашия Next.js проект
Преди да се потопите в Route Handlers, уверете се, че имате настроен Next.js проект с директорията app
. Ако започвате нов проект, използвайте следната команда:
npx create-next-app@latest my-nextjs-app
Изберете директорията app
по време на процеса на настройка, за да активирате новата система за маршрутизация.
Създаване на първия ви Route Handler
Нека създадем проста API крайна точка, която връща JSON отговор. Създайте нова директория в директорията app
, например /app/api/hello
. Вътре в тази директория създайте файл с име route.ts
(или route.js
, ако не използвате TypeScript).
Ето кода за вашия първи Route Handler:
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Здравейте от Next.js Route Handlers!' });
}
Обяснение:
import { NextResponse } from 'next/server';
: Импортира обектаNextResponse
, който се използва за конструиране на API отговори.export async function GET(request: Request) { ... }
: Дефинира асинхронна функция, която обработва GET заявки към крайната точка/api/hello
. Параметърътrequest
предоставя достъп до входящия обект на заявката.return NextResponse.json({ message: 'Здравейте от Next.js Route Handlers!' });
: Създава JSON отговор със съобщение и го връща, използвайкиNextResponse.json()
.
Сега можете да получите достъп до тази крайна точка, като отидете на /api/hello
във вашия браузър или използвате инструмент като curl
или Postman
.
Обработка на различни HTTP методи
Route Handlers поддържат различни HTTP методи като GET, POST, PUT, DELETE, PATCH и OPTIONS. Можете да дефинирате отделни функции за всеки метод в рамките на един и същ файл route.ts
.
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Логика за извличане на всички потребители от базата данни
const users = [{ id: 1, name: 'Иван Петров' }, { id: 2, name: 'Мария Иванова' }]; // Примерни данни
return NextResponse.json(users);
}
export async function POST(request: Request) {
const data = await request.json(); // Парсване на тялото на заявката като JSON
// Логика за създаване на нов потребител в базата данни, използвайки 'data'
const newUser = { id: 3, name: data.name, email: data.email }; // Пример
return NextResponse.json(newUser, { status: 201 }); // Връщане на новия потребител със статус код 201 Created
}
Обяснение:
- Функцията
GET
извлича списък с потребители (симулиран тук) и ги връща като JSON отговор. - Функцията
POST
парсва тялото на заявката като JSON, създава нов потребител (симулирано) и връща новия потребител със статус код 201 Created.
Достъп до данните от заявката
Обектът request
предоставя достъп до различна информация за входящата заявка, включително хедъри, параметри на заявката (query parameters) и тялото на заявката.
Хедъри (Headers)
Можете да получите достъп до хедърите на заявката, като използвате свойството request.headers
:
export async function GET(request: Request) {
const userAgent = request.headers.get('user-agent');
console.log('User Agent:', userAgent);
return NextResponse.json({ userAgent });
}
Параметри на заявката (Query Parameters)
За достъп до параметрите на заявката можете да използвате конструктора URL
:
export async function GET(request: Request) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const id = searchParams.get('id');
console.log('ID:', id);
return NextResponse.json({ id });
}
Тяло на заявката (Request Body)
За POST, PUT и PATCH заявки можете да получите достъп до тялото на заявката, като използвате методите request.json()
или request.text()
, в зависимост от типа на съдържанието.
export async function POST(request: Request) {
const data = await request.json();
console.log('Данни:', data);
return NextResponse.json({ receivedData: data });
}
Връщане на отговори
Обектът NextResponse
се използва за конструиране на API отговори. Той предоставя няколко метода за задаване на хедъри, статус кодове и тела на отговорите.
JSON отговори
Използвайте метода NextResponse.json()
, за да върнете JSON отговори:
return NextResponse.json({ message: 'Успех!', data: { name: 'Иван Петров' } }, { status: 200 });
Текстови отговори
Използвайте конструктора new Response()
, за да върнете обикновени текстови отговори:
return new Response('Здравей, свят!', { status: 200, headers: { 'Content-Type': 'text/plain' } });
Пренасочвания (Redirects)
Използвайте NextResponse.redirect()
, за да пренасочите потребителите към друг URL адрес:
import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.redirect(new URL('/new-location', request.url));
}
Задаване на хедъри
Можете да зададете персонализирани хедъри, като използвате опцията headers
в NextResponse.json()
или new Response()
:
return NextResponse.json({ message: 'Успех!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });
Интеграция на Middleware
Middleware ви позволява да изпълнявате код преди заявката да бъде обработена от вашия Route Handler. Това е полезно за автентикация, оторизация, логване и други свързани задачи.
За да създадете middleware, създайте файл с име middleware.ts
(или middleware.js
) в директорията app
или в някоя нейна поддиректория. Middleware ще се прилага за всички маршрути в тази директория и нейните поддиректории.
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/protected/:path*'], // Приложи този middleware към пътища, започващи с /protected/
};
Обяснение:
- Функцията
middleware
проверява за автентикационен токен в бисквитките на заявката. - Ако токенът липсва, тя пренасочва потребителя към страницата за вход.
- В противен случай, тя позволява на заявката да продължи към Route Handler.
- Обектът
config
указва, че този middleware трябва да се прилага само за маршрути, започващи с/protected/
.
Обработка на грешки
Правилната обработка на грешки е от решаващо значение за изграждането на стабилни API-та. Можете да използвате блокове try...catch
, за да обработвате изключения и да връщате подходящи отговори за грешки.
export async function GET(request: Request) {
try {
// Симулиране на грешка
throw new Error('Нещо се обърка!');
} catch (error: any) {
console.error('Грешка:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Обяснение:
- Блокът
try...catch
улавя всички изключения, които възникват в Route Handler. - В блока
catch
грешката се записва в лога и се връща отговор за грешка със статус код 500 Internal Server Error.
Поточни отговори (Streaming Responses)
Route Handlers поддържат поточни отговори, което ви позволява да изпращате данни инкрементално към клиента. Това е особено полезно за големи набори от данни или дълготрайни процеси.
import { Readable } from 'stream';
import { NextResponse } from 'next/server';
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Симулиране на забавяне
yield `Част от данни ${i}\n`;
}
}
export async function GET(request: Request) {
const readableStream = Readable.from(generateData());
return new Response(readableStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
Обяснение:
- Функцията
generateData
е асинхронен генератор, който произвежда части от данни със забавяне. - Методът
Readable.from()
създава четим поток от генератора. - Обектът
Response
се създава с четимия поток като тяло, а хедърътContent-Type
е зададен наtext/plain
.
Автентикация и оторизация
Защитата на вашите API крайни точки е от решаващо значение. Можете да внедрите автентикация и оторизация, като използвате middleware или директно във вашите Route Handlers.
Автентикация
Автентикацията проверява самоличността на потребителя, който прави заявката. Често срещаните методи за автентикация включват:
- JWT (JSON Web Tokens): Генерирайте токен при успешно влизане и го проверявайте при последващи заявки.
- Автентикация базирана на сесии: Използвайте бисквитки за съхранение на идентификатори на сесии и ги проверявайте при всяка заявка.
- OAuth: Делегирайте автентикацията на доставчик на трета страна като Google или Facebook.
Ето пример за JWT автентикация с помощта на middleware:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET || 'your-secret-key'; // Заменете със силен, произволно генериран таен ключ
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.json({ message: 'Необходима е автентикация' }, { status: 401 });
}
try {
jwt.verify(token, secret);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Невалиден токен' }, { status: 401 });
}
}
export const config = {
matcher: ['/api/protected/:path*'],
};
Оторизация
Оторизацията определя до какви ресурси има достъп даден потребител. Това обикновено се основава на роли или разрешения.
Можете да внедрите оторизация във вашите Route Handlers, като проверявате ролите или разрешенията на потребителя и връщате грешка, ако те нямат достъп.
// app/api/admin/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Да приемем, че имате функция за получаване на ролята на потребителя от токена или сесията
const userRole = await getUserRole(request);
if (userRole !== 'admin') {
return NextResponse.json({ message: 'Неоторизиран достъп' }, { status: 403 });
}
// Логика за извличане на администраторски данни
const adminData = { message: 'Администраторски данни' };
return NextResponse.json(adminData);
}
async function getUserRole(request: Request): Promise {
// Заменете с вашата реална логика за извличане на ролята на потребителя от заявката
// Това може да включва проверка на JWT токен или проверка на сесия
return 'admin'; // Пример: твърдо кодирана роля за демонстрация
}
Внедряване на Route Handlers
Route Handlers се внедряват като сървърлес функции на избрания от вас хостинг доставчик. Next.js поддържа различни платформи за внедряване, включително Vercel, Netlify, AWS и други.
За Vercel внедряването е толкова просто, колкото свързването на вашето Git хранилище с Vercel и пушването на вашия код. Vercel автоматично открива вашия Next.js проект и внедрява вашите Route Handlers като сървърлес функции.
Напреднали техники
Edge функции
Route Handlers могат да бъдат внедрени като Edge функции, които се изпълняват на ръба (edge) на CDN мрежа, по-близо до вашите потребители. Това може значително да намали латентността и да подобри производителността.
За да внедрите Route Handler като Edge функция, добавете edge
runtime към вашия файл route.ts
:
export const runtime = 'edge';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Здравейте от Edge!' });
}
Сървърни действия (Server Actions)
Сървърните действия ви позволяват да изпълнявате код от страна на сървъра директно от вашите React компоненти. Route Handlers и Server Actions работят безпроблемно заедно, което ви позволява лесно да изграждате сложни приложения.
Ето пример за използване на Server Action за извикване на Route Handler:
// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
async function handleSubmit(data: FormData) {
'use server';
const name = data.get('name');
const email = data.get('email');
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name, email }),
});
if (response.ok) {
router.refresh(); // Опресняване на страницата, за да се отразят промените
}
}
export default function MyComponent() {
const router = useRouter();
return (
);
}
Кеширане
Кеширането може значително да подобри производителността на вашите API крайни точки. Можете да използвате хедъра Cache-Control
, за да контролирате как вашите отговори се кешират от браузърите и CDN мрежите.
return NextResponse.json({ message: 'Успех!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });
Този пример задава хедъра Cache-Control
на public, max-age=3600
, което казва на браузърите и CDN мрежите да кешират отговора за един час.
Добри практики
- Използвайте TypeScript: Възползвайте се от типовата безопасност на TypeScript, за да подобрите качеството на кода и да предотвратите грешки.
- Валидирайте заявките: Валидирайте входящите заявки, за да осигурите целостта на данните и да предотвратите злонамерен вход.
- Обработвайте грешките елегантно: Внедрете правилна обработка на грешки, за да предоставяте информативни съобщения за грешки на клиентите.
- Защитете вашите крайни точки: Внедрете автентикация и оторизация, за да защитите вашите API крайни точки.
- Използвайте Middleware: Използвайте middleware за свързани задачи като автентикация, логване и валидация на заявки.
- Кеширайте отговорите: Използвайте кеширане, за да подобрите производителността на вашите API крайни точки.
- Наблюдавайте вашите API-та: Наблюдавайте вашите API-та, за да идентифицирате и разрешавате проблеми бързо.
- Документирайте вашите API-та: Документирайте вашите API-та, за да ги направите лесни за използване от други разработчици. Обмислете използването на инструменти като Swagger/OpenAPI за документация на API.
Примери от реалния свят
Ето няколко примера от реалния свят за това как могат да се използват Route Handlers:
- API за електронна търговия: Създайте API крайни точки за управление на продукти, поръчки и потребители.
- API за социални медии: Създайте API крайни точки за публикуване на туитове, следване на потребители и извличане на хронологии.
- API за система за управление на съдържанието (CMS): Създайте API крайни точки за управление на съдържание, потребители и настройки.
- API за анализ на данни: Създайте API крайни точки за събиране и анализ на данни. Например, Route Handler може да получава данни от проследяващи пиксели на различни уебсайтове и да агрегира информацията за отчитане.
Пример за международна електронна търговия: Route Handler, използван за извличане на цени на продукти въз основа на държавата на потребителя. Крайната точка може да използва геолокацията на заявката (получена от IP адреса), за да определи местоположението на потребителя и да върне цени в съответната валута. Това допринася за локализирано пазаруване.
Пример за глобална автентикация: Route Handler, който внедрява многофакторна автентикация (MFA) за потребители по целия свят. Това може да включва изпращане на SMS кодове или използване на приложения за автентикация, като същевременно се спазват регулациите за поверителност и телекомуникационните инфраструктури на различните региони.
Многоезично доставяне на съдържание: Route Handler, който доставя съдържание на предпочитания от потребителя език. Това може да се определи от хедъра `Accept-Language` в заявката. Този пример подчертава необходимостта от правилно кодиране в UTF-8 и поддръжка на езици, които се пишат отдясно наляво, когато е уместно.
Заключение
Next.js Route Handlers предоставят мощен и гъвкав начин за създаване на API крайни точки директно във вашето Next.js приложение. Като използвате Route Handlers, можете лесно да изграждате стабилни API-та, да разполагате вашата бекенд логика заедно с вашите React компоненти и да се възползвате от функции като middleware, стрийминг и Edge функции.
Това цялостно ръководство обхвана всичко от основна настройка до напреднали техники. Като следвате добрите практики, очертани в това ръководство, можете да изграждате висококачествени API-та, които са сигурни, производителни и лесни за поддръжка.