Concepto clave
La validación y manejo de errores en Server Actions es el proceso de asegurar que los datos que llegan a tu servidor sean correctos y de responder adecuadamente cuando algo falla. Imagina que eres un recepcionista en un hotel: primero verificas que la reserva del cliente tenga todos los datos necesarios (validación), y si falta algo, le explicas claramente qué necesita corregir (manejo de errores), en lugar de simplemente rechazarlo sin más.
En Next.js 15, con Server Components y Streaming SSR, este proceso es crucial porque las acciones del servidor se ejecutan directamente en el entorno del servidor, sin pasar por una API tradicional. Esto significa que debes validar tanto en el cliente (para experiencia de usuario) como en el servidor (para seguridad), y manejar errores de forma que el usuario entienda qué pasó, especialmente cuando usas streaming, donde la interfaz puede actualizarse progresivamente.
Cómo funciona en la práctica
Vamos a crear una Server Action para registrar un usuario, con validación y manejo de errores paso a paso. Primero, define la acción en un archivo separado, por ejemplo actions/register.ts:
// actions/register.ts
'use server';
import { z } from 'zod';
const userSchema = z.object({
email: z.string().email('Email inválido'),
password: z.string().min(8, 'La contraseña debe tener al menos 8 caracteres'),
name: z.string().min(2, 'El nombre debe tener al menos 2 caracteres'),
});
export async function registerUser(formData: FormData) {
try {
const rawData = {
email: formData.get('email'),
password: formData.get('password'),
name: formData.get('name'),
};
// Validación con Zod
const validatedData = userSchema.parse(rawData);
// Lógica de negocio, ej., guardar en base de datos
// Simulamos un error de base de datos
const dbResult = await saveToDatabase(validatedData);
if (!dbResult.success) {
throw new Error('Error al guardar en la base de datos');
}
return { success: true, message: 'Usuario registrado exitosamente' };
} catch (error) {
if (error instanceof z.ZodError) {
return {
success: false,
errors: error.errors.map(e => ({ field: e.path[0], message: e.message }))
};
}
return {
success: false,
message: error instanceof Error ? error.message : 'Error desconocido'
};
}
}
async function saveToDatabase(data: any) {
// Simulación de operación de base de datos
return Math.random() > 0.5 ? { success: true } : { success: false };
}Luego, en tu componente, usa useActionState (en Next.js 15) para manejar el estado de la acción y mostrar errores:
// app/register/page.tsx
'use client';
import { useActionState } from 'react';
import { registerUser } from '@/actions/register';
export default function RegisterPage() {
const [state, action, isPending] = useActionState(registerUser, null);
return (
{state?.errors?.find(e => e.field === 'email') && (
{state.errors.find(e => e.field === 'email').message}
)}
{state?.errors?.find(e => e.field === 'password') && (
{state.errors.find(e => e.field === 'password').message}
)}
{state?.errors?.find(e => e.field === 'name') && (
{state.errors.find(e => e.field === 'name').message}
)}
{isPending ? 'Registrando...' : 'Registrarse'}
{state?.message && (
{state.message}
)}
);
}Caso de estudio
Imagina que estás construyendo una app de e-commerce con Next.js 15. Tienes una Server Action para procesar pedidos. Los datos del pedido incluyen:
| Campo | Tipo | Validación |
|---|---|---|
| productId | string | Debe ser un UUID válido |
| quantity | number | Debe ser mayor a 0 y menor a 100 |
| shippingAddress | string | Debe tener al menos 10 caracteres |
Usa Zod para definir el esquema y maneja errores específicos: si el producto no existe, devuelve "Producto no encontrado"; si el stock es insuficiente, devuelve "Stock insuficiente". Con Streaming SSR, puedes mostrar un mensaje de "Procesando pedido..." mientras se valida y luego actualizar a éxito o error sin recargar la página.
En producción, siempre valida en el servidor, incluso si ya lo hiciste en el cliente, para prevenir ataques de manipulación de datos.
Errores comunes
- Validar solo en el cliente: Los usuarios pueden deshabilitar JavaScript o manipular las solicitudes. Siempre valida también en el servidor con una librería como Zod o Yup.
- Mensajes de error genéricos: Evita mensajes como "Algo salió mal". En su lugar, proporciona detalles específicos, como "El email ya está registrado" o "La contraseña es demasiado corta".
- No manejar errores asíncronos: Si tu Server Action llama a una API externa o base de datos, envuelve esas llamadas en try-catch para capturar y manejar errores de red o de servidor.
- Ignorar el estado de carga: Con Server Actions y Streaming, usa
useActionStateo similar para mostrar indicadores de carga (comoisPending), mejorando la experiencia de usuario. - Exponer detalles internos en errores: No devuelvas mensajes de error que revelen información sensible, como detalles de la base de datos. En su lugar, registra esos errores internamente y muestra un mensaje amigable al usuario.
Checklist de dominio
- ¿Puedes definir un esquema de validación con Zod para una Server Action que incluya al menos tres campos con reglas diferentes?
- ¿Sabes usar
useActionStateen un componente cliente para manejar el estado de una Server Action, incluyendo errores y carga? - ¿Puedes diferenciar entre errores de validación (ej., datos inválidos) y errores de negocio (ej., stock insuficiente) y manejarlos por separado?
- ¿Entiendes cómo el Streaming SSR afecta la visualización de errores y mensajes de éxito en tiempo real?
- ¿Has implementado validación tanto en cliente (para feedback inmediato) como en servidor (para seguridad) en un proyecto real?
- ¿Puedes escribir pruebas unitarias para una Server Action que verifiquen los casos de éxito y error?
- ¿Sabes configurar un middleware de logging para registrar errores de Server Actions sin afectar la respuesta al usuario?
Implementa una Server Action con validación y manejo de errores para un formulario de contacto
En este ejercicio, crearás una Server Action en Next.js 15 para manejar un formulario de contacto, con validación robusta y manejo de errores apropiado. Sigue estos pasos:
- Crea un nuevo proyecto Next.js 15 o usa uno existente. Asegúrate de tener el App Router habilitado.
- En la carpeta
app/contact, crea un archivopage.tsxque sea un componente cliente. Este debe contener un formulario con los siguientes campos:- Nombre (texto, requerido, mínimo 2 caracteres)
- Email (email, requerido, formato válido)
- Mensaje (textarea, requerido, mínimo 10 caracteres)
- En la carpeta
actions, crea un archivocontact.ts. Define una Server Action llamadasubmitContactFormque:- Use Zod para validar los datos del formulario según las reglas anteriores.
- Simule el envío del mensaje (puedes usar un
setTimeoutpara simular una operación asíncrona). - Maneje errores: si la validación falla, devuelve errores específicos por campo; si hay un error en el envío simulado, devuelve un mensaje genérico pero informativo.
- Devuelva un objeto con
successymessageoerrors.
- En el componente
page.tsx, importa la Server Action y usauseActionStatepara manejar el estado. Muestra:- Mensajes de error debajo de cada campo si la validación falla.
- Un mensaje general de éxito o error después del envío.
- Un botón que se deshabilite (
disabled) mientras la acción está en progreso (isPending).
- Prueba el formulario: envía con datos válidos, con datos inválidos, y simula un error en el envío (por ejemplo, lanzando un error aleatorio en la acción). Verifica que los mensajes se muestren correctamente.
- Usa
z.string().email()de Zod para validar el campo email, yz.string().min()para los otros campos. - En
useActionState, el primer argumento es la Server Action, y el estado inicial puede sernull. Accede a los errores constate?.errors. - Para simular un error en el envío, puedes agregar
if (Math.random() > 0.5) throw new Error('Error de red simulado');en la acción después de la validación.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.