Français

Apprenez à créer de puissants points de terminaison d'API avec les Route Handlers de Next.js. Ce guide couvre tout, de la configuration de base aux techniques avancées, avec des exemples pratiques et les meilleures pratiques.

Route Handlers Next.js : Un Guide Complet pour la Création de Points de Terminaison d'API

Next.js a révolutionné la façon dont nous construisons des applications web avec ses fonctionnalités puissantes comme le rendu côté serveur, la génération de sites statiques et, maintenant, les Route Handlers. Les Route Handlers offrent un moyen flexible et efficace de créer des points de terminaison d'API directement au sein de votre application Next.js. Ce guide explore le concept des Route Handlers, leurs avantages et comment les utiliser efficacement pour construire des API robustes.

Que sont les Route Handlers de Next.js ?

Les Route Handlers sont des fonctions définies dans le répertoire app d'un projet Next.js qui traitent les requêtes HTTP entrantes. Contrairement à l'ancienne approche pages/api (qui utilise les API Routes), les Route Handlers offrent un moyen plus simple et plus flexible de définir des points de terminaison d'API à côté de vos composants React. Ce sont essentiellement des fonctions sans serveur (serverless) exécutées à la périphérie (edge) ou dans l'environnement serveur de votre choix.

Considérez les Route Handlers comme la logique backend de votre application Next.js, responsable du traitement des requêtes, de l'interaction avec les bases de données et du renvoi des réponses.

Avantages de l'utilisation des Route Handlers

Configurer votre projet Next.js

Avant de plonger dans les Route Handlers, assurez-vous d'avoir un projet Next.js configuré avec le répertoire app. Si vous démarrez un nouveau projet, utilisez la commande suivante :

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

Choisissez le répertoire app pendant le processus d'installation pour activer le nouveau système de routage.

Créer votre premier Route Handler

Créons un point de terminaison d'API simple qui renvoie une réponse JSON. Créez un nouveau répertoire dans le répertoire app, par exemple, /app/api/hello. À l'intérieur de ce répertoire, créez un fichier nommé route.ts (ou route.js si vous n'utilisez pas TypeScript).

Voici le code de votre premier Route Handler :

// 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!' });
}

Explication :

Maintenant, vous pouvez accéder à ce point de terminaison en naviguant vers /api/hello dans votre navigateur ou en utilisant un outil comme curl ou Postman.

Gérer les différentes méthodes HTTP

Les Route Handlers prennent en charge diverses méthodes HTTP comme GET, POST, PUT, DELETE, PATCH et OPTIONS. Vous pouvez définir des fonctions distinctes pour chaque méthode dans le même fichier route.ts.

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

export async function GET(request: Request) {
 // Logique pour récupérer tous les utilisateurs de la base de données
 const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Données d'exemple
 return NextResponse.json(users);
}

export async function POST(request: Request) {
 const data = await request.json(); // Analyser le corps de la requête en JSON
 // Logique pour créer un nouvel utilisateur dans la base de données en utilisant 'data'
 const newUser = { id: 3, name: data.name, email: data.email }; // Exemple
 return NextResponse.json(newUser, { status: 201 }); // Renvoyer le nouvel utilisateur avec un code de statut 201 Created
}

Explication :

Accéder aux données de la requête

L'objet request fournit un accès à diverses informations sur la requête entrante, y compris les en-têtes, les paramètres de requête et le corps de la requête.

En-têtes

Vous pouvez accéder aux en-têtes de la requête en utilisant la propriété request.headers :

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

Paramètres de requête

Pour accéder aux paramètres de requête, vous pouvez utiliser le constructeur 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 });
}

Corps de la requête

Pour les requêtes POST, PUT et PATCH, vous pouvez accéder au corps de la requête en utilisant les méthodes request.json() ou request.text(), en fonction du type de contenu.

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

Renvoyer des réponses

L'objet NextResponse est utilisé pour construire les réponses de l'API. Il fournit plusieurs méthodes pour définir les en-têtes, les codes de statut et les corps de réponse.

Réponses JSON

Utilisez la méthode NextResponse.json() pour renvoyer des réponses JSON :

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

Réponses texte

Utilisez le constructeur new Response() pour renvoyer des réponses en texte brut :

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

Redirections

Utilisez NextResponse.redirect() pour rediriger les utilisateurs vers une URL différente :

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));
}

Définir les en-têtes

Vous pouvez définir des en-têtes personnalisés en utilisant l'option headers dans NextResponse.json() ou new Response() :

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

Intégration de Middleware

Le middleware vous permet d'exécuter du code avant qu'une requête ne soit traitée par votre Route Handler. C'est utile pour l'authentification, l'autorisation, la journalisation et d'autres préoccupations transversales.

Pour créer un middleware, créez un fichier nommé middleware.ts (ou middleware.js) dans le répertoire app ou n'importe quel sous-répertoire. Le middleware s'appliquera à toutes les routes de ce répertoire et de ses sous-répertoires.

// 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*'], // Appliquer ce middleware aux chemins commençant par /protected/
};

Explication :

Gestion des erreurs

Une gestion appropriée des erreurs est cruciale pour construire des API robustes. Vous pouvez utiliser des blocs try...catch pour gérer les exceptions et renvoyer des réponses d'erreur appropriées.

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

Explication :

Réponses en streaming

Les Route Handlers prennent en charge les réponses en streaming, ce qui vous permet d'envoyer des données de manière incrémentielle au client. C'est particulièrement utile pour les grands ensembles de données ou les processus de longue durée.

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)); // Simuler un délai
 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' },
 });
}

Explication :

Authentification et autorisation

La sécurisation de vos points de terminaison d'API est cruciale. Vous pouvez mettre en œuvre l'authentification et l'autorisation en utilisant un middleware ou directement dans vos Route Handlers.

Authentification

L'authentification vérifie l'identité de l'utilisateur qui effectue la requête. Les méthodes d'authentification courantes incluent :

Voici un exemple d'authentification JWT utilisant un 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'; // Remplacez par un secret fort généré aléatoirement

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*'],
};

Autorisation

L'autorisation détermine à quelles ressources un utilisateur est autorisé à accéder. Ceci est généralement basé sur des rôles ou des permissions.

Vous pouvez mettre en œuvre l'autorisation dans vos Route Handlers en vérifiant les rôles ou les permissions de l'utilisateur et en renvoyant une erreur s'il n'a pas l'accès.

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

export async function GET(request: Request) {
 // Supposons que vous ayez une fonction pour obtenir le rôle de l'utilisateur à partir du jeton ou de la session
 const userRole = await getUserRole(request);

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

 // Logique pour récupérer les données de l'administrateur
 const adminData = { message: 'Admin data' };
 return NextResponse.json(adminData);
}

async function getUserRole(request: Request): Promise {
 // Remplacez par votre logique réelle pour extraire le rôle de l'utilisateur de la requête
 // Cela pourrait impliquer la vérification d'un jeton JWT ou la vérification d'une session
 return 'admin'; // Exemple : rôle codé en dur pour la démonstration
}

Déployer les Route Handlers

Les Route Handlers sont déployés en tant que fonctions sans serveur (serverless) sur le fournisseur d'hébergement de votre choix. Next.js prend en charge diverses plateformes de déploiement, notamment Vercel, Netlify, AWS, et plus encore.

Pour Vercel, le déploiement est aussi simple que de connecter votre dépôt Git à Vercel et de pousser votre code. Vercel détecte automatiquement votre projet Next.js et déploie vos Route Handlers en tant que fonctions sans serveur.

Techniques avancées

Edge Functions

Les Route Handlers peuvent être déployés en tant que Edge Functions, qui sont exécutées à la périphérie d'un CDN, plus près de vos utilisateurs. Cela peut réduire considérablement la latence et améliorer les performances.

Pour déployer un Route Handler en tant que Edge Function, ajoutez le runtime edge à votre fichier 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

Les Server Actions vous permettent d'exécuter du code côté serveur directement depuis vos composants React. Les Route Handlers et les Server Actions fonctionnent parfaitement ensemble, vous permettant de construire des applications complexes avec aisance.

Voici un exemple d'utilisation d'une Server Action pour appeler un 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(); // Rafraîchir la page pour refléter les changements
 }
}

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

 return (
 




); }

Mise en cache

La mise en cache peut améliorer considérablement les performances de vos points de terminaison d'API. Vous pouvez utiliser l'en-tête Cache-Control pour contrôler la manière dont vos réponses sont mises en cache par les navigateurs et les CDN.

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

Cet exemple définit l'en-tête Cache-Control sur public, max-age=3600, ce qui indique aux navigateurs et aux CDN de mettre en cache la réponse pendant une heure.

Meilleures pratiques

Exemples concrets

Voici quelques exemples concrets de la manière dont les Route Handlers peuvent être utilisés :

Exemple de E-commerce international : Un Route Handler utilisé pour récupérer les prix des produits en fonction du pays de l'utilisateur. Le point de terminaison pourrait utiliser la géolocalisation de la requête (dérivée de l'adresse IP) pour déterminer l'emplacement de l'utilisateur et renvoyer les prix dans la devise appropriée. Cela contribue à une expérience d'achat localisée.

Exemple d'authentification globale : Un Route Handler mettant en œuvre l'authentification multifacteur (MFA) pour les utilisateurs du monde entier. Cela pourrait impliquer l'envoi de codes SMS ou l'utilisation d'applications d'authentification, tout en respectant les réglementations sur la confidentialité et les infrastructures de télécommunication des différentes régions.

Livraison de contenu multilingue : Un Route Handler qui livre le contenu dans la langue préférée de l'utilisateur. Celle-ci peut être déterminée à partir de l'en-tête `Accept-Language` dans la requête. Cet exemple souligne la nécessité d'un encodage UTF-8 correct et du support des langues s'écrivant de droite à gauche, le cas échéant.

Conclusion

Les Route Handlers de Next.js offrent un moyen puissant et flexible de créer des points de terminaison d'API directement au sein de votre application Next.js. En tirant parti des Route Handlers, vous pouvez construire des API robustes avec facilité, colocaliser votre logique backend avec vos composants React et profiter de fonctionnalités comme les middlewares, le streaming et les Edge Functions.

Ce guide complet a couvert tout, de la configuration de base aux techniques avancées. En suivant les meilleures pratiques décrites dans ce guide, vous pouvez construire des API de haute qualité qui sont sécurisées, performantes et maintenables.