Español

Aprende a crear potentes endpoints de API usando los Route Handlers de Next.js. Esta guía cubre todo, desde la configuración básica hasta técnicas avanzadas, con ejemplos prácticos y mejores prácticas.

Route Handlers de Next.js: Una Guía Completa para la Creación de Endpoints de API

Next.js ha revolucionado la forma en que construimos aplicaciones web con sus potentes características como el renderizado del lado del servidor, la generación de sitios estáticos y, ahora, los Route Handlers. Los Route Handlers proporcionan una forma flexible y eficiente de crear endpoints de API directamente dentro de tu aplicación Next.js. Esta guía explora el concepto de los Route Handlers, sus beneficios y cómo usarlos eficazmente para construir APIs robustas.

¿Qué son los Route Handlers de Next.js?

Los Route Handlers son funciones definidas dentro del directorio app de un proyecto Next.js que manejan las solicitudes HTTP entrantes. A diferencia del antiguo enfoque pages/api (que utiliza Rutas de API), los Route Handlers ofrecen una manera más optimizada y flexible de definir endpoints de API junto a tus componentes de React. Son esencialmente funciones sin servidor ejecutadas en el borde o en el entorno de servidor que elijas.

Piensa en los Route Handlers como la lógica del backend de tu aplicación Next.js, responsables de procesar solicitudes, interactuar con bases de datos y devolver respuestas.

Beneficios de Usar Route Handlers

Configurando tu Proyecto de Next.js

Antes de sumergirte en los Route Handlers, asegúrate de tener un proyecto de Next.js configurado con el directorio app. Si estás comenzando un nuevo proyecto, usa el siguiente comando:

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

Elige el directorio app durante el proceso de configuración para habilitar el nuevo sistema de enrutamiento.

Creando tu Primer Route Handler

Vamos a crear un endpoint de API simple que devuelva una respuesta JSON. Crea un nuevo directorio dentro del directorio app, por ejemplo, /app/api/hello. Dentro de este directorio, crea un archivo llamado route.ts (o route.js si no estás usando TypeScript).

Aquí está el código para tu primer 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!' });
}

Explicación:

Ahora, puedes acceder a este endpoint navegando a /api/hello en tu navegador o usando una herramienta como curl o Postman.

Manejando Diferentes Métodos HTTP

Los Route Handlers soportan varios métodos HTTP como GET, POST, PUT, DELETE, PATCH y OPTIONS. Puedes definir funciones separadas para cada método dentro del mismo archivo route.ts.

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

export async function GET(request: Request) {
 // Lógica para recuperar todos los usuarios de la base de datos
 const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Datos de ejemplo
 return NextResponse.json(users);
}

export async function POST(request: Request) {
 const data = await request.json(); // Analiza el cuerpo de la solicitud como JSON
 // Lógica para crear un nuevo usuario en la base de datos usando 'data'
 const newUser = { id: 3, name: data.name, email: data.email }; // Ejemplo
 return NextResponse.json(newUser, { status: 201 }); // Devuelve el nuevo usuario con un código de estado 201 Created
}

Explicación:

Accediendo a los Datos de la Solicitud

El objeto request proporciona acceso a diversa información sobre la solicitud entrante, incluyendo encabezados, parámetros de consulta y el cuerpo de la solicitud.

Encabezados

Puedes acceder a los encabezados de la solicitud usando la propiedad request.headers:

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

Parámetros de Consulta

Para acceder a los parámetros de consulta, puedes usar el constructor 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 });
}

Cuerpo de la Solicitud

Para solicitudes POST, PUT y PATCH, puedes acceder al cuerpo de la solicitud usando los métodos request.json() o request.text(), dependiendo del tipo de contenido.

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

Devolviendo Respuestas

El objeto NextResponse se utiliza para construir respuestas de API. Proporciona varios métodos para establecer encabezados, códigos de estado y cuerpos de respuesta.

Respuestas JSON

Usa el método NextResponse.json() para devolver respuestas JSON:

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

Respuestas de Texto

Usa el constructor new Response() para devolver respuestas de texto plano:

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

Redirecciones

Usa NextResponse.redirect() para redirigir a los usuarios a una URL diferente:

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

Estableciendo Encabezados

Puedes establecer encabezados personalizados usando la opción headers en NextResponse.json() o new Response():

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

Integración de Middleware

El middleware te permite ejecutar código antes de que una solicitud sea manejada por tu Route Handler. Esto es útil para la autenticación, autorización, registro y otras preocupaciones transversales.

Para crear un middleware, crea un archivo llamado middleware.ts (o middleware.js) en el directorio app o en cualquier subdirectorio. El middleware se aplicará a todas las rutas dentro de ese directorio y sus subdirectorios.

// 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*'], // Aplica este middleware a rutas que comiencen con /protected/
};

Explicación:

Manejo de Errores

El manejo adecuado de errores es crucial para construir APIs robustas. Puedes usar bloques try...catch para manejar excepciones y devolver respuestas de error apropiadas.

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

Explicación:

Respuestas en Streaming

Los Route Handlers soportan respuestas en streaming, lo que te permite enviar datos de forma incremental al cliente. Esto es particularmente útil para grandes conjuntos de datos o procesos de larga duración.

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)); // Simula un retraso
 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' },
 });
}

Explicación:

Autenticación y Autorización

Asegurar tus endpoints de API es crucial. Puedes implementar la autenticación y la autorización usando middleware o directamente dentro de tus Route Handlers.

Autenticación

La autenticación verifica la identidad del usuario que realiza la solicitud. Los métodos de autenticación comunes incluyen:

Aquí hay un ejemplo de autenticación JWT usando 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'; // Reemplaza con un secreto fuerte y generado aleatoriamente

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

Autorización

La autorización determina a qué recursos puede acceder un usuario. Esto generalmente se basa en roles o permisos.

Puedes implementar la autorización dentro de tus Route Handlers verificando los roles o permisos del usuario y devolviendo un error si no tienen acceso.

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

export async function GET(request: Request) {
 // Asume que tienes una función para obtener el rol del usuario desde el token o la sesión
 const userRole = await getUserRole(request);

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

 // Lógica para recuperar datos de administrador
 const adminData = { message: 'Admin data' };
 return NextResponse.json(adminData);
}

async function getUserRole(request: Request): Promise {
 // Reemplaza con tu lógica real para extraer el rol del usuario de la solicitud
 // Esto podría implicar verificar un token JWT o una sesión
 return 'admin'; // Ejemplo: rol hardcodeado para la demostración
}

Desplegando Route Handlers

Los Route Handlers se despliegan como funciones sin servidor en tu proveedor de hosting elegido. Next.js soporta varias plataformas de despliegue, incluyendo Vercel, Netlify, AWS y más.

Para Vercel, el despliegue es tan simple como conectar tu repositorio de Git a Vercel y subir tu código. Vercel detecta automáticamente tu proyecto de Next.js y despliega tus Route Handlers como funciones sin servidor.

Técnicas Avanzadas

Edge Functions

Los Route Handlers se pueden desplegar como Edge Functions, que se ejecutan en el borde de una CDN, más cerca de tus usuarios. Esto puede reducir significativamente la latencia y mejorar el rendimiento.

Para desplegar un Route Handler como una Edge Function, añade el runtime edge a tu archivo 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

Las Server Actions te permiten ejecutar código del lado del servidor directamente desde tus componentes de React. Los Route Handlers y las Server Actions funcionan juntos sin problemas, permitiéndote construir aplicaciones complejas con facilidad.

Aquí hay un ejemplo de cómo usar una Server Action para llamar a 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(); // Refresca la página para reflejar los cambios
 }
}

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

 return (
 




); }

Almacenamiento en Caché

El almacenamiento en caché puede mejorar significativamente el rendimiento de tus endpoints de API. Puedes usar el encabezado Cache-Control para controlar cómo tus respuestas son almacenadas en caché por los navegadores y las CDNs.

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

Este ejemplo establece el encabezado Cache-Control en public, max-age=3600, lo que indica a los navegadores y CDNs que almacenen en caché la respuesta durante una hora.

Mejores Prácticas

Ejemplos del Mundo Real

Aquí hay algunos ejemplos del mundo real de cómo se pueden usar los Route Handlers:

Ejemplo de comercio electrónico internacional: Un Route Handler utilizado para recuperar los precios de los productos según el país del usuario. El endpoint podría usar la geolocalización de la solicitud (derivada de la dirección IP) para determinar la ubicación del usuario y devolver los precios en la moneda apropiada. Esto contribuye a una experiencia de compra localizada.

Ejemplo de autenticación global: Un Route Handler que implementa la autenticación multifactor (MFA) para usuarios de todo el mundo. Esto podría implicar el envío de códigos SMS o el uso de aplicaciones de autenticación, respetando al mismo tiempo las regulaciones de privacidad y las infraestructuras de telecomunicaciones de las diferentes regiones.

Entrega de contenido multilingüe: Un Route Handler que entrega contenido en el idioma preferido del usuario. Esto se puede determinar a partir del encabezado `Accept-Language` en la solicitud. Este ejemplo resalta la necesidad de una codificación UTF-8 adecuada y soporte para idiomas de derecha a izquierda cuando sea apropiado.

Conclusión

Los Route Handlers de Next.js proporcionan una forma potente y flexible de crear endpoints de API directamente dentro de tu aplicación Next.js. Al aprovechar los Route Handlers, puedes construir APIs robustas con facilidad, colocar tu lógica de backend junto a tus componentes de React y aprovechar características como middleware, streaming y Edge Functions.

Esta guía completa ha cubierto todo, desde la configuración básica hasta las técnicas avanzadas. Siguiendo las mejores prácticas descritas en esta guía, puedes construir APIs de alta calidad que sean seguras, de alto rendimiento y fáciles de mantener.