¿Cómo implementar una aplicación React con PostgreSQL?

PostgreSQL es un sistema avanzado de gestión de bases de datos relacionales preparado para empresas con muchos casos de uso. Actualmente es la segunda base de datos SQL más popular, justo después de MySQL.

En este artículo, profundizamos en la esencia de PostgreSQL, exploramos las distinciones entre bases de datos SQL y NoSQL y brindamos una guía paso a paso sobre cómo implementar una aplicación web respaldada por PostgreSQL.

¿Qué es PostgreSQL?

PostgreSQL es una base de datos relacional de objetos gratuita y de código abierto que admite SQL y JSON.

Se lanzó inicialmente en 1996, por lo que se considera un sistema de gestión de bases de datos relacionales (RDBMS, del inglés “relational database management system”) maduro, robusto y seguro.

Postgres se puede utilizar como base de datos de transacciones de propósito general, base de datos geoespacial, base de datos de aplicaciones web dinámicas, base de datos federada y más.

En comparación con otras bases de datos populares como MySQL, admite herencia de tablas, tipos definidos por el usuario, replicación asíncrona y control de concurrencia de múltiples versiones (MVCC, del inglés “multi-version concurrency control”).

Es conocido por su rendimiento, escalabilidad, extensibilidad, tolerancia a fallas y cumplimiento de ACID.

El RDBMS es compatible con la mayoría de los principales sistemas operativos, incluidos Windows, Linux y macOS.

Además, es compatible con los lenguajes de programación más populares, como Java, Python, C, Go, Perl y JavaScript.

Bases de datos SQL frente a NoSQL

Las bases de datos se pueden dividir en dos categorías según su estructura de datos:

  • Bases de datos relacionales (SQL)
  • Bases de datos no relacionales (NoSQL)

Bases de datos relacionales (SQL)

Las bases de datos relacionales utilizan SQL o lenguaje de consulta estructurado. SQL es un lenguaje de dominio específico que se utiliza para la consulta y manipulación de datos.

El lenguaje admite comandos, transacciones y procedimientos integrados simples, como funciones o vistas almacenadas.

Las bases de datos SQL se basan en esquemas predefinidos. Están compuestos por tablas con un conjunto de columnas, cada una con su propio tipo de datos. Suelen tener propiedades ACID:

  • Atomicidad
  • Consistencia
  • Aislamiento
  • Durabilidad

Las bases de datos SQL se han utilizado ampliamente desde la década de 1970.

Las bases de datos SQL más populares son MySQL, PostgreSQL, SQLite y Oracle Database.

Bases de datos no relacionales (NoSQL)

Las bases de datos no relacionales o bases de datos no SQL no siguen un esquema estricto. Son perfectos para almacenar enormes cantidades de datos dinámicos o no estructurados, generalmente JSON.

Existen varios tipos de bases de datos NoSQL, que incluyen:

  • Bases de datos de documentos
  • Bases de datos de valores clave
  • Bases de datos de gráficos

En los últimos años, las bases de datos NoSQL se han vuelto cada vez más populares debido a la disponibilidad de grandes cantidades de datos no estructurados.

Las bases de datos NoSQL más utilizadas incluyen Redis, Cassandra y AWS DynamoDB.

¿Cuál es mejor SQL o NoSQL?

La elección entre bases de datos SQL y NoSQL depende de su caso de uso y de sus datos.

Si está tratando con grandes cantidades de datos no estructurados, definitivamente opte por NoSQL. Por otro lado, si sus datos están mayoritariamente estructurados, SQL es una mejor opción.

Otros dos factores que debes considerar son el rendimiento y la escala. Las bases de datos NoSQL tienden a ser más rápidas que las bases de datos SQL.

Las bases de datos SQL solo pueden escalar verticalmente, mientras que las bases de datos NoSQL pueden escalar horizontalmente.

Finalmente, algunos marcos web solo admiten bases de datos SQL, mientras que otros solo admiten NoSQL.

¿Cómo implementar una aplicación React con PostgreSQL?

En esta sección de artículo, aprenderá cómo implementar una aplicación web respaldada por Postgres en Back4app.

Requisitos previos

¿Qué es la pila Back4app?

Antes de profundizar en el proceso de implementación, analicemos brevemente qué soluciones ofrece Back4app.

  • Back4app (BaaS) es una solución backend completa. Incluye gestión de usuarios, autenticación, bases de datos en tiempo real (NoSQL o PostgreSQL), ejecución de código personalizado, API generadas automáticamente, SDK, notificaciones push y más.
  • Back4app Containers (CaaS) es una plataforma de implementación y administración de contenedores basada en Docker. ¡Le permite activar contenedores Docker con unos pocos clics!
  • Back4app AI-agent es un nuevo agente impulsado por IA. Le permite realizar todas las tareas relacionadas con la nube con el poder de la conversación. El agente se integra estrechamente con las otras dos soluciones Back4app.

A lo largo del artículo, usaremos Back4app BaaS y Back4app Containers. Sin embargo, debería consultar ¿Cómo utilizar la IA para el desarrollo web? para aprender cómo aprovechar la IA para acelerar su proceso de desarrollo.

Descripción general del proyecto

Construiremos una aplicación web sencilla de seguimiento de presupuestos. La aplicación web permitirá a los usuarios agregar gastos, eliminarlos y calcular diferentes estadísticas (por ejemplo, cantidad gastada, porcentaje del presupuesto).

La aplicación se dividirá en backend y frontend. El backend se construirá con Back4app (respaldado por PostgreSQL) y el frontend se construirá con React (usando Next.js).

Conectaremos los dos usando el SDK de Parse e implementaremos la interfaz en Back4app Containers.

Backend

Comencemos con el backend.

Crear aplicación Back4app

Para crear una aplicación Back4app, primero navegue hasta su panel de Back4app y haga clic en “Crear nueva aplicación”.

Back4app Build New App

A continuación, seleccione “Backend como servicio”, ya que estamos creando un backend.

Back4app Backend as a Service

Asigne a su aplicación un nombre descriptivo, seleccione “PostgreSQL” como base de datos y haga clic en “Crear”.

Back4app App Configuration

Al momento de escribir este artículo, no hay mucha diferencia entre los dos tipos de bases de datos desde el punto de vista del desarrollador. Los mismos métodos del SDK de Parse se aplican a ambos.

Back4app tardará un poco en preparar todo lo necesario para su aplicación. Eso incluye la base de datos, la capa de aplicación, el escalado automático, la copia de seguridad automática y la configuración de seguridad.

Tan pronto como su aplicación esté lista, será redirigido a la vista de la base de datos en tiempo real de la aplicación.

Back4app Database View

Arquitectura de base de datos

Continuando, diseñemos la base de datos.

Dado que nuestra aplicación es relativamente simple, solo necesitaremos una clase. Llamémosla Gasto.

Para crear una nueva clase de base de datos, haga clic en “Crear una clase”, asígnele el nombre Gasto y asegúrese de que esté marcado “Lectura y escritura pública habilitada”.

Back4app Create New Class

Habilitar la lectura y escritura públicas se considera una mala práctica, ya que permite que cualquiera realice operaciones CRUD en sus clases. La seguridad está fuera del alcance de este artículo. Aun así, podría ser una buena idea echar un vistazo a Parse Server Security.

De forma predeterminada, las clases de bases de datos vienen con los siguientes cuatro campos:

+-----------+------------------------------------------------------------------------+
| Name      | Explanation                                                            |
+-----------+------------------------------------------------------------------------+
| objectId  | Object's unique identifier                                             |
+-----------+------------------------------------------------------------------------+
| updatedAt | Date time of the object's last update.                                 |
+-----------+------------------------------------------------------------------------+
| createdAt | Date time of object's creation.                                        |
+-----------+------------------------------------------------------------------------+
| ACLs      | Allow you to control the access to the object (e.g. read, update).     |
+-----------+------------------------------------------------------------------------+

Écheles un vistazo rápido, ya que los usaremos al construir la interfaz.

A continuación, agregue los siguientes campos a la clase de Gasto:

+-----------+-------------+--------------------+----------+
| Data type | Name        | Default value      | Required |
+-----------+-------------+--------------------+----------+
| String    | name        | <leave blank>      | yes      |
+-----------+-------------+--------------------+----------+
| String    | description | <leave blank>      | no       |
+-----------+-------------+--------------------+----------+
| Number    | price       | 0                  | yes      |
+-----------+-------------+--------------------+----------+

Después de eso, complete la base de datos con algunos datos de muestra.

Cree algunos artículos proporcionando los nombres, descripciones y precios. Alternativamente, puede importar este volcado de datos.

Back4app Database Populated

Los datos de prueba nos permitirán posteriormente probar el backend y el frontend.

Cloud Code

Back4app le permite ejecutar código JavaScript personalizado a través de funciones de Cloud Code. Las funciones pueden programarse como trabajos o invocarse mediante solicitudes Parse o HTTP.

Dado que funcionan dentro de un entorno administrado, eso elimina la necesidad de manejar y escalar sus propios servidores.

Para obtener más información sobre las funciones como servicio (FaaS), consulte ¿Qué son las funciones sin servidor?

Utilizaremos una función de Cloud Code para calcular las estadísticas de gastos.

Para crear una, seleccione “Código de nube > Funciones y alojamiento web” en la barra lateral. Luego abra cloud/main.js y pegue el siguiente código:

// cloud/main.js

const totalBudget = 100;

Parse.Cloud.define("getStatistics", async (request) => {
  const query = new Parse.Query("Expense");
  const totalExpenses = await query.count();
  const results = await query.find();

  const totalSpent = results.reduce(
    (sum, expense) => sum + expense.get("price"), 0);
  const spentPercentage = totalSpent > 0 ? 
    Math.round((totalSpent / totalBudget) * 100) : 0;

  return {
    totalExpenses,
    totalSpent,
    totalBudget,
    spentPercentage
  };
});
  1. Este código define una nueva función de Cloud Code denominada getStatistics.
  2. La función agrega los datos y calcula el gasto total y el porcentaje gastado.

Por último, haga clic en “Implementar” para implementar la función en la nube.

Y con esto hemos terminado con el backend. ¡Eso fue fácil!

Frontend

En esta sección de artículo, implementaremos la interfaz de la aplicación.

Crear siguiente aplicación

La forma más sencilla de iniciar una aplicación Next.js es mediante la utilidad create-next-app. Para usarlo, abra la terminal y ejecute el siguiente comando:

$ npx create-next-app@latest back4app-postgres

√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@)? ... No

Creating a new Next.js app in /back4app-postgres.

Creando una nueva aplicación Next.js en /back4app-postgres.

Si nunca ha utilizado la utilidad create-next-app, se instalará automáticamente.

Asegúrese de habilitar TailwindCSS ya que lo usaremos en lugar de una biblioteca de componentes.

A continuación, limpie el proyecto iniciado eliminando primero el contenido de la carpeta public/.

Manteniendo solo las primeras tres líneas de src/app/globals.css:

/* app/src/globals.css */
@tailwind base; @tailwind components; @tailwind utilities;

Y reemplazando app/src/globals.css con el siguiente código:

// src/app/page.js 
export default function Page() { 
  return ( 
      <p>Back4app rocks!</p> 
  ); 
}

Inicie el servidor de desarrollo:

$ next dev

Abra su navegador web favorito y navegue hasta http://localhost:3000/. Debería ver el mensaje “¡Back4app es genial!” si todo va bien.

Vistas

El frontend tendrá los siguientes puntos finales:

  1. / muestra la tabla de gastos y estadísticas de gastos
  2. /add/ muestra un formulario para agregar un nuevo gasto
  3. /delete/<objectId>/ muestra una confirmación para eliminar un gasto

Para implementar estos puntos finales, cree la siguiente estructura de directorios:

src/
├── add/
│   └── page.js
└── delete/
    └── [objectId]/
        └── page.js

Además, cree la carpeta components con Container.js Header.js:

src/
└── components/
    ├── Container.js
    └── Header.js

Pegue lo siguiente en Container.js:

// src/app/components/Container.js

const Container = ({children}) => {
  return (
    <div className="container mx-auto px-4 sm:px-6 lg:px-8">
      {children}
    </div>
  )
}

export default Container;

Y haz lo mismo para Header.js:

// src/app/components/Header.js

import Container from "@/app/components/Container";
import Link from "next/link";

const Header = () => {
  return (
    <Container>
      <div className="py-4">
        <Link href="/">
          <div 
            className="text-2xl font-semibold text-indigo-500 hover:text-indigo-700"
          >
            back4app-postgres
          </div>
        </Link>
      </div>
    </Container>
  )
}

export default Header;

Usa Container.js y Header.js en layout.js de la siguiente manera:

// src/app/layout.js

"use client";

import {Inter} from "next/font/google";
import "./globals.css";
import Header from "@/app/components/Header";
import Container from "@/app/components/Container";

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Header/>
        <Container>
          {children}
        </Container>
      </body>
    </html>
  );
}

Finalmente, pegue el código de vista en los archivos en consecuencia:

  1. src/app/page.js
  2. src/app/add/page.js
  3. src/app/delete/[objectId]/page.js

Vuelva a ejecutar el servidor de desarrollo y visite http://localhost:3000 en su navegador. Debería ver algo similar a esto:

Back4app App Postgress

Al hacer clic en el botón “Agregar gastos”, se le redirigirá al formulario de adición de gastos.

Parse SDK

Hay varias formas de conectarse a un backend de Back4app:

  1. RESTful API
  2. GraphQL API
  3. Parse SDK

Optaremos por este último ya que es la configuración más sólida y sencilla.

El SDK de Parse es un conjunto de herramientas repleto de herramientas útiles para consultar datos, administrarlos, ejecutar funciones de Cloud Code y más.

Está disponible para muchos lenguajes y marcos de programación, como JavaScript, PHP, Flutter y Objective-C.

Comience instalando Parse a través de npm:

$ npm install parse

Para usar Parse en nuestras vistas de React, primero tenemos que inicializarlo. Pero antes de hacer eso, crearemos un contexto de React, que nos permitirá pasar la instancia de Parse a todas nuestras vistas.

Cree una carpeta context en la carpeta src/app y un archivo parseContext.js en ella:

import {createContext} from "react";

const ParseContext = createContext();

export default ParseContext;

Luego inicialice Parse en layout.js y envuelva toda la aplicación con ParseContext.Provider de esta manera:

// src/app/layout.js

import Parse from "parse/dist/parse";
import ParseContext from "@/app/context/parseContext";

Parse.initialize(
  "<your_parse_application_id>",
  "<your_parse_javascript_key>",
);
Parse.serverURL = "https://parseapi.back4app.com/";

export default function RootLayout({ children }) {
  return (
    <ParseContext.Provider value={Parse}>
      <html lang="en">
        // ...
      </html>
    </ParseContext.Provider>
  );
}

Asegúrese de reemplazar <your_parse_application_id> y <your_parse_javascript_key> con sus claves reales. Para obtenerlos, navegue hasta su panel de Back4app y seleccione “Configuración de la aplicación> Seguridad y claves” en la barra lateral.

Back4app API Keys

Ahora podemos obtener la instancia de Parse en nuestras vistas de esta manera:

const parse = useContext(ParseContext);

Luego, modifique ligeramente las vistas para invocar métodos de Parse.

src/app/page.js:

// src/app/page.js

export default function Page() {

  // ...

  const parse = useContext(ParseContext);

  const fetchExpenses = () => {
    const query = new parse.Query("Expense");
    query.find().then((fetchedExpenses) => {
      const expenses = fetchedExpenses.map(expense => ({
        objectId: expense.id,
        name: expense.get("name"),
        description: expense.get("description"),
        price: expense.get("price"),
        createdAt: expense.get("createdAt"),
      }));
      setExpenses(expenses);
      console.log("Expenses fetched successfully.");
    }).catch((error) => {
      console.error("Error while fetching expenses:", error);
    });
  }

  const fetchStatistics = () => {
    parse.Cloud.run("getStatistics").then((statistics) => {
      setStatistics(statistics);
      console.log("Statistics fetched successfully.");
    }).catch((error) => {
      console.error("Error while fetching statistics:", error);
    });
  }

  // ...
}

src/app/add/page.js:

// src/app/add/page.js

export default function Page() {

  // ...

  const parse = useContext(ParseContext);

  const onAddClick = () => {
    const Expense = parse.Object.extend("Expense");
    const expense = new Expense();

    expense.set("name", name);
    expense.set("description", description);
    expense.set("price", parseFloat(price));

    expense.save().then((expense) => {
        console.log("Expense created successfully with objectId: ", expense.id);
        router.push("/");
      }, (error) => {
        console.error("Error while creating expense: ", error);
      }
    );
  }

  const onCancelClick = () => {
    router.push("/");
  }

  // ...
}

src/app/delete/[objectId]/page.js:

// src/app/delete/[objectId]/page.js

export default function Page() {

  // ...

  const parse = useContext(ParseContext);

  const onDeleteClick = () => {
    const Expense = parse.Object.extend("Expense");
    const query = new parse.Query(Expense);

    query.get(objectId).then((expense) => {
      return expense.destroy();
    }).then((response) => {
      console.log("Expense deleted successfully");
      router.push("/");
    }).catch((error) => {
      console.error("Error while deleting expense: ", error);
    });
  }

  const onCancelClick = () => {
    router.push("/");
  }

  // ...
}

No se olvide de las importaciones en la parte superior del archivo:

import {useContext} from "react";
import ParseContext from "@/app/context/parseContext";

Genial, eso es todo.

Su frontend ahora está conectado al backend. Si visita la aplicación en su navegador, debería ver que los datos se cargan correctamente desde el backend. Todos los cambios en el frontend ahora se reflejan en el backend.

Dockerizar

Dado que Back4app Containers es una plataforma CaaS, su proyecto debe estar acoplado antes de la implementación. La forma recomendada de acoplar su proyecto es mediante un Dockerfile.

Un Dockerfile es un script de modelo que proporciona instrucciones para crear una imagen de contenedor.

Cree un Dockerfile en la raíz del proyecto:

# Dockerfile

FROM node:18

WORKDIR /app
COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build
RUN npm install -g next

EXPOSE 3000

CMD ["next", "start", "-p", "3000"]

Este Dockerfile utiliza la imagen node:18-alpine, establece el directorio de trabajo, administra las dependencias, copia el proyecto y crea la aplicación.

Al finalizar, expone el puerto 3000 e inicia un servidor Next.js para escuchar en ese puerto.

A continuación, cree un archivo .dockerignore para minimizar el tamaño de la imagen:

# .dockerignore

.idea/

node_modules/
.next/
/out/
build/

.vercel

.dockerignore funcionan de manera similar a los archivos .gitignore .

Asegúrese de que todo funcione compilando y ejecutando la imagen localmente:

$ docker build -t back4app-postgres:1.0 .
$ docker run -it -p 3000:3000 back4app-postgres:1.0

Abra su navegador web y navegue hasta http://localhost:3000. La aplicación web aún debería ser completamente funcional.

Enviar a VCS

Para implementar su código en Back4app Containers, debe enviarlo a GitHub.

  1. Inicie sesión en su cuenta de GitHub.
  2. Cree un nuevo repositorio.
  3. Copie la URL de origen remoto, por ejemplo, [email protected]:duplxey/repo.git.
  4. Inicializar el repositorio de Git: git init
  5. Agregue el control remoto: git remote add origin <your_remote_origin_url>
  6. Agregue todos los archivos: git add.
  7. Cree una confirmación: git commit -m “project init”
  8. Empuje el código fuente: git push origin main

Abra su navegador web favorito y asegúrese de que todo el código esté agregado al repositorio.

Implemente el código

Ahora que la aplicación está acoplada y alojada en GitHub, finalmente podemos implementarla.

Navegue hasta su panel de Back4app y haga clic en el botón “Crear nueva aplicación” una vez más.

Back4app Build New App

Seleccione “Contenedores como servicio”, ya que estamos implementando una aplicación dockerizada.

Back4app Containers as a Service

Si es la primera vez que trabaja con Back4app Containers, debe vincular su GitHub a su cuenta Back4app.

Al elegir a qué repositorios tiene acceso Back4app, asegúrese de permitir el acceso al repositorio creado en el paso anterior.

A continuación, “Seleccione” el repositorio.

Back4app Select Repository

Los contenedores Back4app le permiten configurar ajustes de implementación como puerto, implementación automática, variables ambientales y comprobaciones de estado.

Dado que nuestra aplicación es simple, debemos proporcionar un nombre y podemos mantener todo lo demás como predeterminado.

Back4app Configure Deployment

Al hacer clic en “Crear aplicación”, Back4app extraerá el código de GitHub, creará la imagen de Docker, la enviará al registro del contenedor y la implementará.

Después de unos momentos, su aplicación estará disponible en la URL de la barra lateral.

Back4app Successful Deployment

Conclusión

En este artículo, ha aprendido qué es PostgreSQL, las diferencias entre las bases de datos SQL y NoSQL y cómo implementar una aplicación web respaldada por Postgres en Back4app.

Para poner a prueba su comprensión, le sugiero que implemente algunas de estas ideas:

  • Autenticación de usuario
  • En lugar de tener un presupuesto global, hágalo basado en el usuario.
  • Agregue un dominio personalizado a la aplicación Back4app Containers

Obtenga el código fuente final del repositorio back4app-postgres.


Leave a reply

Your email address will not be published.