Integración de React Server Components con PostgreSQL

Clase 5 de 24Curso de Next.js Avanzado

Resumen

La integración de React Server Components con bases de datos como PostgreSQL ofrece una arquitectura potente y segura para manejar datos sensibles en aplicaciones modernas. Aquí exploramos cómo construir una aplicación con esta tecnología, realizando consultas SQL sin intermediarios y maximizando la seguridad y eficiencia de tu backend.

¿Qué ventajas ofrecen los React Server Components para proteger datos?

  • Protección del código del navegador: React Server Components permiten que el código sensible permanezca en el servidor, enviando al cliente solo el HTML necesario.
  • Minimización de exposición: Los navegadores no acceden directamente a las APIs o secretos del servidor, reduciendo riesgos de seguridad.
  • Separación de lógica cliente-servidor: Next.js gestiona esta separación automáticamente, facilitando la implementación de buenas prácticas.

¿Cómo conectar PostgreSQL directamente desde un React Server Component?

  1. Configuración de la base de datos:

    • Utiliza psql para crear la base de datos y tablas. En este ejemplo:
      CREATE DATABASE "expense_tracker";
      \c expense_tracker
      CREATE TABLE expenses (
        id SERIAL PRIMARY KEY,
        name TEXT NOT NULL,
        amount NUMERIC NOT NULL,
        date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
      );
      
    • Verifica la estructura desde la línea de comandos o una GUI de PostgreSQL.
  2. Conexión en Next.js:

    • Configura la conexión en un archivo dedicado. Usa librerías como pg:
      const { Pool } = require('pg');
      const pool = new Pool({
        connectionString: process.env.DATABASE_URL,
      });
      module.exports = pool;
      
  3. Consultas directas a SQL:

    • Define funciones para leer y mutar datos:
      const getExpenses = async () => {
        const result = await pool.query('SELECT * FROM expenses ORDER BY date DESC');
        return result.rows;
      };
      
      const addExpense = async (name, amount) => {
        await pool.query('INSERT INTO expenses (name, amount) VALUES ($1, $2)', [name, amount]);
      };
      

¿Cómo integrar consultas con un React Server Component?

  • Uso de funciones asincrónicas: Los componentes de servidor pueden llamar funciones SQL directamente sin intermediarios como ORMs.
  • Ejemplo de lectura y renderizado:
    import { getExpenses } from './db';
    
    export default async function ExpenseTracker() {
      const expenses = await getExpenses();
      return (
        
            {expenses.map(expense => (
              
            ))}
          
    NameAmountDate
    {expense.name} {expense.amount} {expense.date}
    ); }

¿Cómo manejar mutaciones desde el cliente?

  • Uso de formularios y acciones:

    'use client';
    const handleSubmit = async (formData) => {
      const name = formData.get('name');
      const amount = formData.get('amount');
      await fetch('/add-expense', { method: 'POST', body: JSON.stringify({ name, amount }) });
    };
    
  • Revalidación de datos en Next.js:

    • Para actualizar automáticamente la UI tras una mutación:
      import { revalidatePath } from 'next/cache';
      await revalidatePath('/expense-tracker');
      

¿Por qué es más seguro trabajar de esta forma?

  • API oculta al cliente: Next.js genera rutas dinámicas protegidas, dificultando el acceso malicioso.
  • Datos sensibles solo en el servidor: La lógica permanece oculta al navegador.
  • Protección contra ataques automatizados: Al evitar exponer rutas predecibles, se reducen las superficies de ataque.