Skip to content

Latest commit

 

History

History
268 lines (198 loc) · 11.2 KB

GETTING-STARTED-MONGODB.md

File metadata and controls

268 lines (198 loc) · 11.2 KB

Primeros pasos con MongoDB

MongoDB es un base de datos no-relacional, y es la más común (popular) a día de hoy en el ecosistema de Node.js.

Si vas a trabajar con MongoDB y Docker, mejor lee primero la guía de primeros pasos con Docker. Si vas a instalar MongoDB y desarrollar el proyecto sin Docker en este momento, sigue leyendo esta guía.

Una vez creado tu fork y clonado el repo en tu computadora, haces npm install para instalar las dependencias básicas. Antes de poder comenzar a codear, tenemos que crear nuestro entorno de desarrollo. Para ello te recomendamos seguir los siguientes pasos:


1. Instalar MongoDB y Compass

El sitio de MongoDB tiene tutoriales de cómo instalar la Community Edition. Elige tu plataforma (Windows, Mac, Ubuntu etc) y sigue el tutorial.

Con los tutoriales, vas a descargar y instalar MongoDB en tu sistema, con algunas herramientas y comandos para usar en la línea de comando.

También recomendamos que instales Compass, que es un GUI (Graphical User Interface) para interactuar con la base de datos. Puedes interactuar con MongoDB sin Compass y solo en la linea de comando, pero un GUI puede ayudarte visualizar y entender lo que está en la base de datos. Sigue las instrucciones de instalación de Compass.

2. Levanta la base de datos y servidor

Podemos decir que este proyecto tiene dos "servicios", uno es la base de datos para almacenar los productos, usuarios, etc., y el otro es el servidor para exponer el API.

Estos servicios tienen que estar corriendo, para que el API pueda funcionar.

Correr el servidor es bien simple: con npm start va a ejecutar index.js que tiene la lógica básica de un servidor con express.

Cómo levantar el servidor, este depende de tu instalación y sistema. Por ejemplo, en MacOS si instalaste con homebrew, puede usar brew services start mongodb-community@6.0 para levantarlo. O sin homebrew, mongod --config /usr/local/etc/mongod.conf --fork. En Windows, hay que levantarlo desde Services console.

Revisa la guía de instalación de , guía de instalación de Windows, o tu instalación en particular, para ejemplos en cómo levantarlo.

3. Elegir módulo (cliente)

Ahora que ya tenemos un servidor de base de datos, vamos a necesitar elegir un módulo o librería diseñado para interactuar con nuestra base de datos desde Node.js. Existen un montón de opciones, pero para este proyecto te recomendamos usar el Node.js driver de MongoDB que es la forma más directa de interactuar con tu instancia de MongoDB.

Hay que instalar el Node.js Driver en este proyecto usando npm, revisa la documentación oficial para más información.

El boilerplate ya incluye un archivo config.js donde se leen las variables de entorno, y entre ellas está DB_URL. Como vemos ese valor lo estamos asignando en la propiedad dbUrl del módulo config.

// `config.js`
exports.dbUrl = process.env.MONGO_URL || process.env.DB_URL || 'mongodb://127.0.0.1:27017/test';

Ahora que ya sabemos dónde encontrar el connection string (en el módulo config), podemos proceder a establecer una conexión con la base de datos usando el cliente elegido.

Ejemplo de conexión usando MongoDB Node Driver

const { MongoClient } = require('mongodb');
const config = require("./config");

const client = new MongoClient(config.dbUrl);

async function connect() {
  try {
    await client.connect();
    const db = client.db(<NOMBRE_DB>); // Reemplaza <NOMBRE_DB> por el nombre del db
    return db;
  } catch (error) {
    //
  }
}

Puedes encontrar mas ejemplos en la documentación de MongoDB.

4. Definir esquemas

Como parte del proceso de diseño de nuestra base de datos vamos a tener que especificar los esquemas de nuestros modelos de datos. Con esto nos referimos a que tenemos que describir de alguna forma la estructura de las colecciones que vamos a usar y la forma de los objetos que vayamos a guardar en esas colecciones.

Puedes usar la documentación de API que describe la estructura de products, orders, etc. para guiar el diseño.

5. Implementar los primeros TODOs

El boilerplate del proyecto viene con archivos con lógica para arrancar el server y otros que contienen funciones de rutas y autenticación, pero muchas están vacías. Hemos marcado las primeras partes esenciales con comentarios TODO (del inglés por hacer), que es una convención en el desarrollo de software, cuando queda algo pendiente de hacer.

Aquí te guiamos un poco sobre esto TODO's.

TODO 1: Conectar a la base de datos

En el archivo connect.js hay que hacer la conexión con la base de datos.

const { dbUrl } = config;

async function connect() {
  // TODO: Conexión a la Base de Datos
}

Aquí debes usar el dbUrl que importamos del config para establecer la conexión. Las funciones que van a interactuar con la base de datos tienen que invocar connect.

TODO 2: Crear el usuario admin

El proyecto depende en la existencia de un usuario en la base de datos que tiene privilegios de administrador, para así poder crear otros usuarios, etc.

En routes/users.js invocamos una función initAdminUser(app, next) al final de archivo, y definimos esta función arriba en este misma archivo.

initAdminUser está incompleto, y hay un TODO para crear el usuario admin, donde tienes que primero chequear si un admin ya existe, y si no agregar uno a la base de datos.

const initAdminUser = (app, next) => {
  const { adminEmail, adminPassword } = app.get('config');
  if (!adminEmail || !adminPassword) {
    return next();
  }

  const adminUser = {
    email: adminEmail,
    password: bcrypt.hashSync(adminPassword, 10),
    roles: { admin: true },
  };

  // TODO: crear usuaria admin
  next();
};

Puedes confirmar si tu código funciona revisando la base de datos y con un testeo unitario.

TODO 3: Implementar autenticación de usuario

En routes/auth.js está la ruta '/auth' definida, con un

 // TODO: autenticar a la usuarix

Aquí es donde debes verificar que el correo y password coinciden con datos de algún usuario en la base de datos. Si coinciden, hay que generar un JWT token y mandarlo en la respuesta, para que el usuario puede usarlo en sus peticiones futuras. Para ejemplos con mas detalle, busca tutoriales de autenticación con JWT y node/express.

TODO 4: Implementar el middleware de autenticación

En middleware/auth.js hay varios TODOs. Usa esta oportunidad para familiarizarte con el concepto de middleware en express.

La aplicación va a usar este middleware para chequear que las peticiones que requieren autenticación sean autorizados, es decir, que tienen un token válido.

TODO 5: Implementar la ruta GET /users

Para juntar y verificar todo el trabajo que has hecho, seria bueno implementar una ruta básica del API, en este caso recomendamos /users porque ya debes tener el user admin en tu base de datos, y además porque esta ruta usa el middleware de auth.

Vas a ver que la ruta /users usa la función getUsers que está definido en controller/users.js. El concepto de controller nos sirve para separar más la lógica de la definición de rutas con la implementación que va a hablar con el base de datos. Hay que implementar getUsers para obtener la lista de users de la colección en tu base de datos.

Revisa el tutorial de Node y express en Mozilla que habla de controllers.

TODO 6: Implementar la ruta POST /users

Los tests e2e invocan la ruta POST /users para agregar la usuaria para los tests. Por lo tanto, antes de poder ejecutar los tests e2e, esta ruta debe funcionar correctamente.

6. Definir estrategia de pruebas unitarias

Además de las pruebas e2e que ya incluye el boilerplate del proyecto, se espera que puedas también usar pruebas unitarias para el desarrollo de los diferentes endpoints o rutas así como otros módulos internos que decidas desarrollar.

Para hacer pruebas unitarias de rutas de Express, te recomendamos explorar la librería supertest, que puedes usar en combinación con jest.

Otro punto a tener en cuenta en las pruebas unitarias, es cómo mockear la base de datos. Algunas bases de datos ofrecen herramientas (como mongodb-memory-server) que nos permiten usar una base de datos en memoria y así evitar hacer mocks per se, pero por lo general querremos considerar cómo abstraer la interacción con la base de datos para facilitar mocks que nos permitan concentrarnos en la lógica de las rutas.

7. Familiarizarte con las pruebas de integración (e2e)

El boilerplate de este proyecto ya incluye pruebas e2e (end-to-end) o de integración, que se encargan de probar nuestra aplicación en conjunto, a través de la interfaz HTTP. A diferencia de las pruebas unitarias, en vez de importar o requerir un módulo y probar una función de forma aislada, lo que vamos a hacer es arrancar toda la aplicación, y probarla tal como se usaría en el mundo real, para ello la aplicación de prueba necesitará una base de datos y escuchar en un puerto de red.

Para correr pruebas e2e sobre instancia local podemos usar:

npm run test:e2e

Esto levanta la aplicación con npm start y corre los tests contra la URL de esta instancia (por defecto http://127.0.0.1:8080).

Los pruebas e2e dependen del código de (globalSetup.js)[../e2e/globalSetup.js] que jest ejecuta en primer lugar, antes de los tests. Este paso de setup levanta un mock db (como hemos hablado de mongodb-memory-server) y jest se conecta a este mock db.

Para este configuración usamos mongodb-memory-server y un preset jest-mongodb que ya están incluido en el boilerplate.