Implementa CRUD con Server Actions y base de datos

Lectura
25 min~4 min lectura

Concepto clave

En el desarrollo full-stack moderno, Server Actions representan un cambio de paradigma que permite ejecutar código del lado del servidor directamente desde componentes del cliente, sin necesidad de crear APIs REST tradicionales. Imagina que estás en un restaurante: en lugar de tener que llamar al mesero (API endpoint) para cada pedido, ahora puedes cocinar directamente en la cocina (servidor) desde tu mesa (cliente).

En SvelteKit, las Server Actions se definen en archivos +page.server.js o +server.js y se consumen desde componentes Svelte mediante la función enhance. Esto elimina la sobrecarga de crear controladores HTTP separados y simplifica significativamente el flujo de datos entre cliente y servidor. Para operaciones CRUD (Create, Read, Update, Delete), esto significa que puedes manejar toda la lógica de base de datos directamente donde tiene sentido: en el servidor, pero con una sintaxis que se siente como si estuvieras trabajando localmente.

Cómo funciona en la práctica

Vamos a implementar un CRUD completo para nuestra app de tareas en tiempo real. Primero, configuraremos una base de datos PostgreSQL usando Prisma como ORM. Luego, crearemos las Server Actions correspondientes para cada operación CRUD. El flujo es el siguiente:

  1. Definir el esquema de la base de datos en prisma/schema.prisma
  2. Crear migraciones y sincronizar con la base de datos
  3. Implementar Server Actions en src/routes/tasks/+page.server.js
  4. Consumir estas acciones desde el componente +page.svelte
  5. Agregar validaciones y manejo de errores

La magia ocurre cuando SvelteKit automáticamente serializa los datos entre cliente y servidor, manteniendo la seguridad (las acciones solo se ejecutan en el servidor) mientras proporciona una experiencia de desarrollo fluida.

Codigo en accion

Primero, definamos nuestra Server Action para crear una tarea:

// src/routes/tasks/+page.server.js
import { prisma } from '$lib/server/prisma';
import { fail } from '@sveltejs/kit';

export const actions = {
    createTask: async ({ request }) => {
        const data = await request.formData();
        const title = data.get('title');
        const description = data.get('description');
        
        // Validación básica
        if (!title || title.length < 3) {
            return fail(400, { 
                error: 'El título debe tener al menos 3 caracteres',
                title, description
            });
        }
        
        try {
            const task = await prisma.task.create({
                data: {
                    title,
                    description: description || '',
                    completed: false,
                    createdAt: new Date()
                }
            });
            
            return { success: true, task };
        } catch (error) {
            return fail(500, { 
                error: 'Error al crear la tarea',
                title, description
            });
        }
    }
};

Ahora, veamos cómo consumir esta acción desde el componente:

<!-- src/routes/tasks/+page.svelte -->
<script>
    import { enhance } from '$app/forms';
    import { page } from '$app/stores';
    
    let title = '';
    let description = '';
</script>

<form method="POST" action="?/createTask" use:enhance>
    <input 
        type="text" 
        name="title" 
        bind:value={title}
        placeholder="Título de la tarea"
        required
    />
    <textarea 
        name="description"
        bind:value={description}
        placeholder="Descripción (opcional)"
    ></textarea>
    <button type="submit">Crear Tarea</button>
</form>

{#if $page.form?.error}
    <p style="color: red;">{$page.form.error}</p>
{/if}

{#if $page.form?.success}
    <p style="color: green;">Tarea creada exitosamente!</p>
{/if}

Errores comunes

  • Olvidar la validación del lado del servidor: Aunque valides en el cliente, siempre valida en el servidor. Los datos del cliente pueden ser manipulados.
  • No manejar estados de carga: Cuando usas enhance, SvelteKit proporciona el estado $page.form que incluye submitting. Úsalo para deshabilitar botones durante el envío.
  • Exponer errores internos al cliente: En producción, nunca devuelvas mensajes de error detallados de la base de datos. Usa logs en el servidor y mensajes genéricos al cliente.
  • No limpiar formularios después del éxito: Después de una acción exitosa, limpia los campos del formulario para una mejor UX.
  • Ignorar la concurrencia: En apps en tiempo real, múltiples usuarios pueden modificar los mismos datos. Implementa optimisic updates o versionado.

Checklist de dominio

  1. Puedo crear una Server Action que interactúe con una base de datos real
  2. Sé cómo validar datos tanto en cliente como en servidor
  3. Implementé al menos 3 operaciones CRUD completas usando Server Actions
  4. Manejo estados de error y éxito apropiadamente en la UI
  5. Uso correctamente el estado $page.form para feedback al usuario
  6. Configuré Prisma correctamente con mi base de datos PostgreSQL
  7. Entiendo la diferencia entre Server Actions y endpoints API tradicionales

Implementa CRUD completo para tareas con Server Actions

En este ejercicio, implementarás un sistema CRUD completo para la app de tareas usando Server Actions de SvelteKit.

  1. Configuración inicial: Asegúrate de tener PostgreSQL corriendo y configurado en tu .env con la variable DATABASE_URL. Ejecuta npx prisma migrate dev para crear las tablas.
  2. Crear (Create): Implementa la acción createTask como se muestra en la lección, pero agrega validación para que la descripción no exceda 500 caracteres.
  3. Leer (Read): Crea una Server Action loadTasks que cargue todas las tareas desde la base de datos y muéstralas en una lista.
  4. Actualizar (Update): Implementa updateTask que permita marcar tareas como completadas/incompletas. Agrega un checkbox junto a cada tarea.
  5. Eliminar (Delete): Crea deleteTask con confirmación antes de eliminar. Usa un botón de eliminar por cada tarea.
  6. Mejoras: Agrega paginación (10 tareas por página) y ordenamiento por fecha de creación descendente.

Entrega: Un repositorio Git con todo el código funcionando y un README que explique tu implementación.

Pistas
  • Usa el hook `use:enhance` en todos tus formularios para mejor UX
  • Para la paginación, considera usar `skip` y `take` en las queries de Prisma
  • Implementa optimistic updates para que la UI responda inmediatamente antes de la confirmación del servidor

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.