SPA con MERN: ejemplo de aplicación web

En este artículo te enseñaré un ejemplo completo de conexión a MongoDB y Express con React. Vamos a usar el stack MERN para hacer un CRUD completo.

Al final tendremos un proyecto completo que será una single page application escrita con React, misma que consumirá una API de Node creada con Express. Los datos van a residir en una base de datos de MongoDB a la que vamos a acceder usando Mongoose.

Como siempre, te explicaré el código más importante a través del post, y te dejaré el repositorio completo al final del post para que puedas explorarlo a tu gusto.

Estructura del proyecto

Aquí solo te mostraré cómo creé el proyecto completo. Si tú tienes otro método puedes omitir este paso.

Primero generé la app de react con Create react app:

En este caso se llama ejemplo-mern. Por defecto el servidor de desarrollo se ejecuta en el puerto 3000. Después en ese mismo directorio abrí otra terminal y para el lado del servidor usé el generador de express. Creé el proyecto con:

express --no-view --git api

Fíjate en que en este caso mi aplicación del servidor se llama api y está en el mismo directorio que mi app de react. Luego ejecuté:

Eso me lo dijo el asistente. Si a ti te dice otra cosa o sabes lo que haces, esto puede cambiar. Más tarde cambié el puerto, ya que el servidor de desarrollo de React escucha (al igual que la app de express por defecto) en el puerto 3000.

Para cambiarlo simplemente editamos el archivo bin/www. Yo lo cambié al puerto 5000:

Y ahora ejecutamos (dentro de api) npm run start o nodemon bin/www en caso de que quieras que el servidor se refresque en cada cambio que haces.

Solo para resumir: el servidor de desarrollo de React quedó en el puerto 3000 y el servidor de Node con Express en el puerto 5000. De este modo ambos proyectos están en el mismo directorio. La estructura final se ve así:

Estructura del proyecto MERN

Obviamente esa es la estructura ya con el código final. Ahora veamos cómo es que se conforma todo esto.

Por cierto, este proyecto se trata sobre la gestión de videojuegos. Algo muy simple pero que sirve perfecto como ejemplo.

Express con Node y MongoDB

Comencemos viendo el lado del servidor. La aplicación de Express queda así:

Solo he modificado lo necesario. Estamos cargando las rutas de los videojuegos en la línea 6. También estamos exponiendo la carpeta public (misma que se encuentra dentro de api) en la línea 21. Esto es importante, pues aquí vamos a colocar la app de React cuando la compilemos.

Además, estamos permitiendo CORS en la línea 10 para el dominio localhost:3000 ya que en modo desarrollo debemos permitir que React realice llamadas a la API de Express desde un dominio distinto. Si cambias el puerto del servidor de desarrollo de React, cámbialo aquí.

Después montamos las rutas de los videojuegos en /videojuegos, lo puedes ver en la línea 23.

Modelo de Mongoose

Antes de pasar a ver cómo creamos nuestra API que va a consumir React, veamos cómo es que nos conectamos a MongoDB usando Mongoose.

Mongoose no es otra cosa más que un tipo de ORM que nos permite definir modelos que más tarde interactúan con la base de datos de MongoDB.

En este caso el modelo queda definido así:

Como puedes ver solo tenemos 3 propiedades. En este caso es el nombre, el precio y la calificación del videojuego. También estamos indicando que los 3 campos son requeridos y que en el caso de los tipos numéricos el mínimo es 0.

Ya hemos definido nuestro modelo, es momento de exponerlo en una API.

Enrutador

Ahora veamos las rutas que van a conformar nuestra API. He definido a las mismas en un archivo separado que estoy importando anteriormente en la app principal. Fíjate cómo estoy importando el modelo definido anteriormente en la línea 3.

Para cada ruta hago una operación en el modelo. Por ejemplo, en el método post agrego un nuevo registro, etcétera. Esto del modelo ya lo he explicado en otro post. Básicamente es hacer todo el CRUD pero separado en cada ruta de Express.

Recuerda que estamos montando este enrutador en /videojuegos y que las rutas son relativas. Así que por ejemplo para obtener todos los videojuegos vamos a hacer una petición GET a localhost:5000/videojuegos.

Lado del cliente con React

Pasemos a la parte de la aplicación web creada con la librería React y JavaScript. Vamos a consumir la API que expusimos anteriormente desde una Single page application.

He usado (además de React, obviamente) Bulma CSS para los estilos. Así que el index de la app web queda así:

Y la app general así:

Estoy usando el enrutador de React o React Router. Básicamente defino un componente por cada ruta. Aquí solo estoy definiendo el layout general y el menú de navegación. Fíjate en que en el caso del formulario para editar videojuegos (línea 20) se recibe el id en la ruta.

A continuación veremos los componentes, pero por el momento veamos el nav:

Es un nav de Bulma CSS. El código que ves es simplemente código para ocultar y mostrar el menú de navegación de bulma en pantallas más pequeñas. Ahora sí veamos los componentes.

Agregar videojuego

Formulario en React para agregar un nuevo videojuego en MongoDB

Veamos el primer componente de react. Es un simple formulario que nos va a servir para guardar un nuevo registro en nuestra base de datos de MongoDB ya en el backend. Lo renderizamos así:

En el change de cada input actualizamos el estado interno de la app:

Y también escuchamos el envío del formulario. Presta especial atención a este método, pues usando fetch vamos a enviar los datos del formulario a Express para que los mismos sean guardados en una base de datos de MongoDB:

La magia está ocurriendo desde la línea 6 hasta la 15. Lo demás es el manejo de la respuesta para mostrar un toast dependiendo de la respuesta.

Y así de simple es como enviamos un dato desde React a MongoDB. Después de eso limpiamos el formulario modificando el estado interno del componente.

El componente completo así como el código de toda la app te la dejaré al final, aquí solo te muestro lo más importante.

Obtener videojuegos

Tabla de datos traídos de Express y MongoDB renderizada con React

Ya tenemos nuestra API conectada a Mongo, es momento de consultar la ruta que nos va a dar todos los videojuegos en forma de arreglo. Para ello tenemos el siguiente componente que hace la petición cuando el mismo se acaba de montar (línea 13 hasta 18) y los muestra en la tabla gracias al método render.

En la línea 39 hasta la 41 estoy dibujando una fila de la tabla (componente propio) por cada videojuego que hay. A continuación vemos esa fila:

Decidí separar este componente de la fila de la tabla por simplicidad, ya que esta fila debe mostrar un enlace para editar el videojuego y un botón para eliminar, pero dejarlo en el componente padre haría que sea bastante código en un solo archivo.

Lo importante aquí es el botón para eliminar que muestra una confirmación de Sweet Alert 2 y en caso de que el usuario confirme, hace una petición DELETE a la API de Express para que a su vez ésta le diga a MongoDB que elimine el documento.

Eliminar documento de MongoDB desde React – Borrar videojuego

Editar documento de MongoDB con React

Formulario de edición – actualizar documento de MongoDB desde React

Ya vimos 3 de 4 operaciones fundamentales. Ahora veamos la última: la edición. En este caso necesitamos consumir dos endpoints de nuestra API.

El primer caso es para obtener los detalles de un videojuego por id (mismo que está en la URL) y rellenar el formulario:

El segundo será cuando ya actualicemos el videojuego con una petición PUT, que será en el envío del formulario:

Y hacemos lo mismo que cuando insertamos un nuevo videojuego, indicamos el éxito con un toast pero en este caso no reiniciamos el formulario.

Código completo

A lo largo del post solo te he explicado los aspectos más importantes, pero no te he mostrado el código completo pues el mismo reside en mi repositorio de GitHub.

Por ejemplo, pudiste ver que importamos el archivo de las constantes, mismo que guarda (y debes cambiarlo en caso necesario) la URL del servidor pero que no lo he mostrado aquí por simplicidad.

Te dejo el código fuente completo en mi GitHub. Recuerda que tanto para la api como para el front-end necesitas ejecutar npm install para instalar las dependencias.

Luego, en ambos lados debes ejecutar (en terminales separadas) npm run start para ejecutar tanto el servidor de la API como el servidor de desarrollo de React.

Esto solo es cuando estés en modo desarrollo, pues cuando pases a producción vas a compilar la app de React y servir los assets con Node, cosa que veremos a continuación.

Preparando para producción

Cuando hayas terminado de modificar la app del lado del cliente (con React) puedes generar un build optimizado. Para ello ejecuta npm run build.

Ese comando va a generar una carpeta llamada build; copia el contenido de la misma en api/public de manera que se ve así:

Desplegar app MERN

Ahora ya no es necesario encender el servidor de desarrollo de React, pues basta con tener el servidor de Node que alberga tanto la API como los archivos estáticos de la SPA.

De hecho si accedes a localhost:5000 verás la aplicación que creamos con React, ya sin tener el servidor de desarrollo:

SPA MERN – Sirviendo archivos estáticos y API con Express y Node

Así es como puedes llevar la app a producción y servir los archivos de manera estática. Eso sí, cuando quieras modificar algo del lado del cliente tendrás que encender el servidor de React, volver a “compilar” y a colocar los archivos en public.

Conclusión

Sé que fue un post algo extenso pero quería asegurarme de dejar todo claro, tanto para descargar el código, ejecutarlo y llevarlo a producción.

Si te interesa también puedes ver cómo conectar PHP con React, o más tutoriales de React, JavaScript y MongoDB.

Encantado de ayudarte


Estoy disponible para trabajar en tu proyecto, modificar el programa del post o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.

No te pierdas ninguno de mis posts

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

3 comentarios en “SPA con MERN: ejemplo de aplicación web”

  1. Muchas gracias por esta entrada. La aplicación la he descargado y funciona, está bien explicado en el blog y es un gusto poder aprender algo así con este detalle y funcionando.

    Solo por si sirve de ayuda para otros:
    – Habría que poner al principio que hace falta un MongoDB (con docker se solventa perfectamente, exportando el puerto 27017 a local).
    – Hace falta una versión más antigua de la actual. Yo he instado Node.js con nvm, la versión 14.21.2, y funciona perfectamente. Con la versión LTS no va.
    – Hay que hacer npm install tanto en /api como en la app principal de React.

    Muchas gracias y un saludo.

Dejar un comentario