Tanto Nuxt como Vue y MongoDB son herramientas que giran en torno a JavaScript y que están hechas para ser utilizadas en el contexto de una aplicación mediana-grande e interactiva. Desplegar un Nuxt o un Vue con Docker no suele suponer un problema, pero muchas veces nos topamos con excepciones que solo se pueden dar cuando juntas varias tecnologías o herramientas y quieres hacerlas funcionar en conjunto. La idea de este artículo es conseguir que una aplicación que use Nuxt.js se pueda comunicar con la base de datos dentro de docker. Es decir, Nuxt.js creará mediante mongoose y Nitro una conexión global al contenedor de mongodb, después mediante el frontend hecho en Vue las peticiones a los endpoints de Nuxt correspondientes para guardar los datos en la base de datos.
Configurando Docker
En este ejemplo usaremos Docker Compose en su última versión, pero seguramente no haya mucha diferencia con la versión previsa (docker-compose).
En la raíz del proyecto crearemos un archivo compose.yml o docker-compose.yml en donde declararemos los contenedores que usaremos siendo el primero la aplicación hecha en Nuxt.js. El puerto, los volúmenes, usuario y demás serán a tu elección. Después del contenedor de la aplicación quedan aquellos que usaremos para ejecutar MongoDB y son dos contenedores según la documentación oficial del plugin de MongoDB de Docker:
mongo: Es el contenedor principal y el que se encarga ejecutar la base de datos. Si buscamos tener persistencia en los datos que se vayan a almacenar dentro, ya sea para testing o en producción, necesitamos declarar una ruta para ello, por ejemplo ./mongodb_data:/data/db:rw. También es recomendable asignar usuario con más privilegios, root.
mongo-express: Este contenedor sirve para lanzar un cliente en donde poder operar con Mongo de forma gráfica. Ofrece una experiencia gráfica para el usuario con la que poder administrar las bases de datos con facilidad, seguridad y rapidez.
Este es un ejemplo de una configuración para un archivo compose.yml:
services:
node:
image: node:20.14.0-slim
container_name: name
command: tail -f /dev/null
working_dir: /app
user: root
volumes:
- .:/app
ports:
- 3000:3000
mongo:
image: mongo
container_name: "name_mongodb"
restart: always
volumes:
- ./mongodb_data:/data/db:rw
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: root
mongo-express:
image: mongo-express
container_name: "name_mongodb_express"
restart: always
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: root
ME_CONFIG_MONGODB_ADMINPASSWORD: root
ME_CONFIG_MONGODB_URL: mongodb://root:root@mongo:27017/
ME_CONFIG_BASICAUTH: false
Documentación oficial en: https://hub.docker.com/_/mongo
Configurando Nuxt
Nuxt.js es un framework que viene a mejorar Vue.js añadiéndole varias capas de funcionalidades extra como el SSR (Server Side Rendering), el enrutado dinámico y estático por defecto, Nitro, etc. Este arículo no trata tanto sobre Nuxt.js sino sobre como usarlo conjuntamente con Docker y MongoDB, pero se puede iniciar una aplicación en Nuxt con el siguiente comando:
npx nuxi@latest init <project-name>
Documentación oficial: https://nuxt.com/docs/getting-started/introduction.
Aparte de toda la configuración de Nuxt.js que es independiente a este artículo, las configuraciones de Nuxt.js para usarlo con Docker y MongoDB son muy sencillas, solo hay que seguir estos dos pasos:
Conexión a la BBDD
Primero necesitamos una conexión con la base de datos, para ello crearemos un archivo (con el nombre que se le quiera asignar) en la carpeta db (o el nombre que se quiera asignar) dentro de la carpeta de server que se encuentra en la raíz del proyecto en Nuxt.js. La carpeta server es donde almacenaremos todos los archivos o scripts relacionados a la parte del servidor, esto debido a que Nuxt es un framework orientado al SSR (Server Side Rendering), por lo tanto todo el código almacenado en server se considerará parte del servidor de la aplicación. Y el archivo de conexión es para crear una única conexión global con la base de datos mediante mongoose y Nitro, de esa forma podremos realizar operaciones con la base de datos en cualquier parte de la aplicación sin necesidad de crear una nueva conexión a la base de datos ocupando toda la RAM en el proceso.
El archivo deberá contener el siguiente código:
import mongoose from "mongoose";
import type { Nitro } from "nitropack";
const URI = process.env.MONGODB_URI || '';
export default async (_nitroapp: Nitro) => {
mongoose.connect(URI).then(() => {
console.log('DB connected');
}).catch((e) => {
console.error(e);
})
}
Para la conexión, en mi caso estoy utilizando mongoose, una librería que actúa como driver para la conexión entre la aplicación y la base de datos. mongoose se encarga principalmente de poder comunicar la aplicación con el contenedor de mongo y de esa forma conectarlo a la base de datos, pero también es útil para crear modelos o simplificar las operaciones.
También es viable usar cualquier otro driver como el original de MongoDB.
nuxt.config.ts
Configurar MongoDB en Nuxt es muy sencillo ya que hay una librería que viene por defecto la cual es indispensable para hacer conexiones globales como esta, se trata de Nitro, un framework diseñado para optimizar la ejecución de código en el backend y para usarlo simplemente habrá que añadir el siguiente código dentro de la función defineNuxtConfig en el archivo nuxt.config.ts que es donde se encuentran las configuraciones globales de Nuxt:
nitro: {
plugins: ['~/server/db/connect.ts']
},
Yo he usado de ejemplo la ruta ~/server/db/connect.ts, pero la idea es usar la ruta al archivo donde se realiza la conexión a la base de datos.
Configuración local
Para terminar de hacer funcionar la conexión con la base de datos ahora toca declarar la variable de entorno que se usa en uno de los archivos editados anteriormente, ./server/<nombre de la carpeta>/<nombre del archivo de conexión>.ts. Para esto, en la raíz del proyecto crearemos un archivo llamado .env y dentro añadiremos una variable llamada MONGODB_URI (el estándar para nombrar variables de entorno de MongoDB) y le asignaremos como valor la URI a nuestra base de datos. Si no asignamos esta variable de entorno, la conexión entre la app y la base de datos fallará debido a que es tanto un método de autenticación como una ruta para que luego el driver que usemos en JavaScript para conectarnos a MongoDB sepa a donde apuntar.
Solo necesitaremos copiar la URL/valor que está asignado a la clave ME_CONFIG_MONGODB_URL dentro del compose.yml que configuramos anteriormente y añadirle al final un “/” y el nombre de nuestra base de datos. En mi caso será mongodb://root:root@mongo:27017/test.
Express
MongoDB Express es una herramienta de interfaz gráfica muy útil a la que podremos acceder desde http://localhost:8081/. Dentro podremos crear, modificar, eliminar, entre otras cosas, todas las bases de datos que tengamos o queramos crear. No es realmente necesario utilizarla pero es una herramienta muy útil para cuando se quiera administrar las bases de datos de forma gráfica e intuitiva.
Cierre
Si bien no me he extendido mucho en Nuxt como tal ya que no forma parte del contexto de este artículo, de todas formas con esto ya deberíamos tener una aplicación en la que se use Vue.js en el frontend de la aplicación pero renderizando el contenido con un backend SSR hecho en Nuxt.js para luego comunicarlo con el contenedor de la base de datos con mongoose y guardando los datos en una base de datos MongoDB, todo esto dentro de Docker y usando contenedores aparte. Repasando un poco, hemos configurado los contenedores del docker, preparado Nuxt habiendo configurado la conexion a la base de datos con mongoose y declarado la conexión de forma global con Nitro, configurado las variables de entorno y probado Express para un manejo de la base de datos más sencillo.