Polski

Dowiedz się, jak tworzyć potężne punkty końcowe API za pomocą Next.js Route Handlers. Ten przewodnik omawia wszystko, od podstawowej konfiguracji po zaawansowane techniki, z praktycznymi przykładami i najlepszymi praktykami.

Next.js Route Handlers: Kompleksowy przewodnik po tworzeniu punktów końcowych API

Next.js zrewolucjonizował sposób, w jaki tworzymy aplikacje internetowe, dzięki swoim potężnym funkcjom, takim jak renderowanie po stronie serwera, generowanie statycznych stron, a teraz także Route Handlers. Route Handlers zapewniają elastyczny i wydajny sposób tworzenia punktów końcowych API bezpośrednio w aplikacji Next.js. Ten przewodnik omawia koncepcję Route Handlers, ich zalety oraz sposoby ich efektywnego wykorzystania do budowy solidnych interfejsów API.

Czym są Next.js Route Handlers?

Route Handlers to funkcje zdefiniowane w katalogu app projektu Next.js, które obsługują przychodzące żądania HTTP. W przeciwieństwie do starszego podejścia pages/api (które używa API Routes), Route Handlers oferują bardziej usprawniony i elastyczny sposób definiowania punktów końcowych API obok komponentów React. Są to w zasadzie funkcje bezserwerowe wykonywane na brzegu sieci (edge) lub w wybranym środowisku serwerowym.

Można myśleć o Route Handlers jako o logice backendowej aplikacji Next.js, odpowiedzialnej za przetwarzanie żądań, interakcję z bazami danych i zwracanie odpowiedzi.

Korzyści z używania Route Handlers

Konfiguracja projektu Next.js

Zanim zagłębisz się w Route Handlers, upewnij się, że masz skonfigurowany projekt Next.js z katalogiem app. Jeśli rozpoczynasz nowy projekt, użyj następującego polecenia:

npx create-next-app@latest my-nextjs-app

Wybierz katalog app podczas procesu konfiguracji, aby włączyć nowy system routingu.

Tworzenie pierwszego Route Handlera

Stwórzmy prosty punkt końcowy API, który zwraca odpowiedź w formacie JSON. Utwórz nowy katalog wewnątrz katalogu app, na przykład /app/api/hello. W tym katalogu utwórz plik o nazwie route.ts (lub route.js, jeśli nie używasz TypeScript).

Oto kod Twojego pierwszego Route Handlera:

// app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
}

Wyjaśnienie:

Teraz możesz uzyskać dostęp do tego punktu końcowego, przechodząc do /api/hello w przeglądarce lub używając narzędzia takiego jak curl lub Postman.

Obsługa różnych metod HTTP

Route Handlers obsługują różne metody HTTP, takie jak GET, POST, PUT, DELETE, PATCH i OPTIONS. Możesz zdefiniować osobne funkcje dla każdej metody w tym samym pliku route.ts.

// app/api/users/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 // Logic to retrieve all users from the database
 const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Example data
 return NextResponse.json(users);
}

export async function POST(request: Request) {
 const data = await request.json(); // Parse the request body as JSON
 // Logic to create a new user in the database using 'data'
 const newUser = { id: 3, name: data.name, email: data.email }; // Example
 return NextResponse.json(newUser, { status: 201 }); // Return the new user with a 201 Created status code
}

Wyjaśnienie:

Dostęp do danych żądania

Obiekt request zapewnia dostęp do różnych informacji o przychodzącym żądaniu, w tym nagłówków, parametrów zapytania i ciała żądania.

Nagłówki

Możesz uzyskać dostęp do nagłówków żądania za pomocą właściwości request.headers:

export async function GET(request: Request) {
 const userAgent = request.headers.get('user-agent');
 console.log('User Agent:', userAgent);
 return NextResponse.json({ userAgent });
}

Parametry zapytania

Aby uzyskać dostęp do parametrów zapytania, możesz użyć konstruktora 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 });
}

Ciało żądania

Dla żądań POST, PUT i PATCH możesz uzyskać dostęp do ciała żądania za pomocą metod request.json() lub request.text(), w zależności od typu zawartości.

export async function POST(request: Request) {
 const data = await request.json();
 console.log('Data:', data);
 return NextResponse.json({ receivedData: data });
}

Zwracanie odpowiedzi

Obiekt NextResponse służy do konstruowania odpowiedzi API. Zapewnia kilka metod ustawiania nagłówków, kodów statusu i ciał odpowiedzi.

Odpowiedzi JSON

Użyj metody NextResponse.json(), aby zwrócić odpowiedzi JSON:

return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });

Odpowiedzi tekstowe

Użyj konstruktora new Response(), aby zwrócić odpowiedzi w postaci zwykłego tekstu:

return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });

Przekierowania

Użyj NextResponse.redirect(), aby przekierować użytkowników na inny adres 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));
}

Ustawianie nagłówków

Możesz ustawić niestandardowe nagłówki za pomocą opcji headers w NextResponse.json() lub new Response():

return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });

Integracja z Middleware

Middleware pozwala na uruchomienie kodu przed obsłużeniem żądania przez Route Handler. Jest to przydatne do uwierzytelniania, autoryzacji, logowania i innych zagadnień przekrojowych.

Aby utworzyć middleware, stwórz plik o nazwie middleware.ts (lub middleware.js) w katalogu app lub dowolnym podkatalogu. Middleware będzie miało zastosowanie do wszystkich tras w tym katalogu i jego podkatalogach.

// 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*'], // Apply this middleware to paths starting with /protected/
};

Wyjaśnienie:

Obsługa błędów

Prawidłowa obsługa błędów jest kluczowa dla budowy solidnych interfejsów API. Możesz użyć bloków try...catch do obsługi wyjątków i zwracania odpowiednich odpowiedzi o błędach.

export async function GET(request: Request) {
 try {
 // Simulate an error
 throw new Error('Something went wrong!');
 } catch (error: any) {
 console.error('Error:', error);
 return NextResponse.json({ error: error.message }, { status: 500 });
 }
}

Wyjaśnienie:

Odpowiedzi strumieniowe

Route Handlers obsługują odpowiedzi strumieniowe, co pozwala na stopniowe wysyłanie danych do klienta. Jest to szczególnie przydatne w przypadku dużych zbiorów danych lub długotrwałych procesów.

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)); // Simulate delay
 yield `Data chunk ${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' },
 });
}

Wyjaśnienie:

Uwierzytelnianie i autoryzacja

Zabezpieczanie punktów końcowych API jest kluczowe. Możesz zaimplementować uwierzytelnianie i autoryzację za pomocą middleware lub bezpośrednio w swoich Route Handlers.

Uwierzytelnianie

Uwierzytelnianie weryfikuje tożsamość użytkownika wysyłającego żądanie. Typowe metody uwierzytelniania to:

Oto przykład uwierzytelniania JWT za pomocą 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'; // Replace with a strong, randomly generated secret

export function middleware(request: NextRequest) {
 const token = request.cookies.get('auth-token')?.value;

 if (!token) {
 return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
 }

 try {
 jwt.verify(token, secret);
 return NextResponse.next();
 } catch (error) {
 return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
 }
}

export const config = {
 matcher: ['/api/protected/:path*'],
};

Autoryzacja

Autoryzacja określa, do jakich zasobów użytkownik ma dostęp. Zazwyczaj opiera się to na rolach lub uprawnieniach.

Możesz zaimplementować autoryzację w swoich Route Handlers, sprawdzając role lub uprawnienia użytkownika i zwracając błąd, jeśli nie ma on dostępu.

// app/api/admin/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 // Assume you have a function to get the user's role from the token or session
 const userRole = await getUserRole(request);

 if (userRole !== 'admin') {
 return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
 }

 // Logic to retrieve admin data
 const adminData = { message: 'Admin data' };
 return NextResponse.json(adminData);
}

async function getUserRole(request: Request): Promise {
 // Replace with your actual logic to extract the user's role from the request
 // This could involve verifying a JWT token or checking a session
 return 'admin'; // Example: hardcoded role for demonstration
}

Wdrażanie Route Handlers

Route Handlers są wdrażane jako funkcje bezserwerowe u wybranego dostawcy hostingu. Next.js obsługuje różne platformy wdrożeniowe, w tym Vercel, Netlify, AWS i inne.

W przypadku Vercel wdrożenie jest tak proste, jak podłączenie repozytorium Git do Vercel i wypchnięcie kodu. Vercel automatycznie wykrywa projekt Next.js i wdraża Route Handlers jako funkcje bezserwerowe.

Zaawansowane techniki

Funkcje brzegowe (Edge Functions)

Route Handlers mogą być wdrażane jako funkcje brzegowe (Edge Functions), które są wykonywane na brzegu sieci CDN, bliżej użytkowników. Może to znacznie zmniejszyć opóźnienia i poprawić wydajność.

Aby wdrożyć Route Handler jako funkcję brzegową, dodaj środowisko uruchomieniowe edge do pliku route.ts:

export const runtime = 'edge';

import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 return NextResponse.json({ message: 'Hello from the Edge!' });
}

Server Actions

Server Actions pozwalają na wykonywanie kodu po stronie serwera bezpośrednio z komponentów React. Route Handlers i Server Actions doskonale ze sobą współpracują, umożliwiając łatwe tworzenie złożonych aplikacji.

Oto przykład użycia Server Action do wywołania Route Handlera:

// 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(); // Refresh the page to reflect the changes
 }
}

export default function MyComponent() {
 const router = useRouter();

 return (
 




); }

Buforowanie (Caching)

Buforowanie może znacznie poprawić wydajność punktów końcowych API. Możesz użyć nagłówka Cache-Control do kontrolowania, jak odpowiedzi są buforowane przez przeglądarki i sieci CDN.

return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });

Ten przykład ustawia nagłówek Cache-Control na public, max-age=3600, co informuje przeglądarki i sieci CDN, aby buforowały odpowiedź przez jedną godzinę.

Najlepsze praktyki

Przykłady z życia wzięte

Oto kilka przykładów z życia wziętych, jak można wykorzystać Route Handlers:

Przykład międzynarodowego e-commerce: Route Handler używany do pobierania cen produktów na podstawie kraju użytkownika. Punkt końcowy mógłby wykorzystać geolokalizację żądania (pochodzącą z adresu IP) do określenia lokalizacji użytkownika i zwrócenia cen w odpowiedniej walucie. Przyczynia się to do zlokalizowanego doświadczenia zakupowego.

Przykład globalnego uwierzytelniania: Route Handler implementujący uwierzytelnianie wieloskładnikowe (MFA) dla użytkowników na całym świecie. Mogłoby to obejmować wysyłanie kodów SMS lub korzystanie z aplikacji uwierzytelniających, z poszanowaniem przepisów dotyczących prywatności i infrastruktury telekomunikacyjnej różnych regionów.

Dostarczanie treści wielojęzycznych: Route Handler dostarczający treść w preferowanym języku użytkownika. Można to określić na podstawie nagłówka `Accept-Language` w żądaniu. Ten przykład podkreśla potrzebę prawidłowego kodowania UTF-8 i wsparcia dla języków pisanych od prawej do lewej, w stosownych przypadkach.

Podsumowanie

Next.js Route Handlers zapewniają potężny i elastyczny sposób tworzenia punktów końcowych API bezpośrednio w aplikacji Next.js. Wykorzystując Route Handlers, można z łatwością budować solidne interfejsy API, umieszczać logikę backendową obok komponentów React i korzystać z funkcji takich jak middleware, streaming i Edge Functions.

Ten kompleksowy przewodnik omówił wszystko, od podstawowej konfiguracji po zaawansowane techniki. Postępując zgodnie z najlepszymi praktykami opisanymi w tym przewodniku, możesz tworzyć wysokiej jakości interfejsy API, które są bezpieczne, wydajne i łatwe w utrzymaniu.