Validación y manejo de errores en Server Actions

Lectura
15 min~6 min lectura

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:

CampoTipoValidación
productIdstringDebe ser un UUID válido
quantitynumberDebe ser mayor a 0 y menor a 100
shippingAddressstringDebe 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 useActionState o similar para mostrar indicadores de carga (como isPending), 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

  1. ¿Puedes definir un esquema de validación con Zod para una Server Action que incluya al menos tres campos con reglas diferentes?
  2. ¿Sabes usar useActionState en un componente cliente para manejar el estado de una Server Action, incluyendo errores y carga?
  3. ¿Puedes diferenciar entre errores de validación (ej., datos inválidos) y errores de negocio (ej., stock insuficiente) y manejarlos por separado?
  4. ¿Entiendes cómo el Streaming SSR afecta la visualización de errores y mensajes de éxito en tiempo real?
  5. ¿Has implementado validación tanto en cliente (para feedback inmediato) como en servidor (para seguridad) en un proyecto real?
  6. ¿Puedes escribir pruebas unitarias para una Server Action que verifiquen los casos de éxito y error?
  7. ¿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:

  1. Crea un nuevo proyecto Next.js 15 o usa uno existente. Asegúrate de tener el App Router habilitado.
  2. En la carpeta app/contact, crea un archivo page.tsx que 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)
  3. En la carpeta actions, crea un archivo contact.ts. Define una Server Action llamada submitContactForm que:
    • Use Zod para validar los datos del formulario según las reglas anteriores.
    • Simule el envío del mensaje (puedes usar un setTimeout para 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 success y message o errors.
  4. En el componente page.tsx, importa la Server Action y usa useActionState para 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).
  5. 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.
Pistas
  • Usa z.string().email() de Zod para validar el campo email, y z.string().min() para los otros campos.
  • En useActionState, el primer argumento es la Server Action, y el estado inicial puede ser null. Accede a los errores con state?.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.