¿Cómo utilizar el patrón MVC (Model View Controller) en 2023?

El patrón MVC puede parecer muy abstracto si no lo has usado en el pasado. En este artículo vamos a explorar lo que es, un caso de uso real y cómo implementarlo utilizando Express js y Postgres.

En este artículo aprenderás:

  1. ¿Qué es el patrón MVC?
  2. ¿Cómo adaptarlo a tecnologías modernas?
  3. ¿Cómo implementarlo en Express js y Postgres?

¿Qué es el patrón MVC (Modelo Vista Controlador)?

"MVC (Modelo-Vista-Controlador) es un patrón en el diseño de software comúnmente utilizado para implementar interfaces de usuario, datos y lógica de control. Enfatiza una separación entre la lógica de negocios y su visualización. Esta "separación de preocupaciones" proporciona una mejor división del trabajo y una mejora de mantenimiento." (Fuente)

Para entender mejor el concepto de MVC vamos a definir cada uno de sus componentes:

  1. Modelo: Usualmente contiene lógica de negocio para leer y escribir información en la base de datos. Recibe peticiones del controlador y hace los cálculos, lecturas y escrituras necesarias para solventar la petición.
  2. Vista: HTML que ve el usuario
  3. Controlador: Código que se encarga de recibir peticiones del usuario, dirigirlos al modelo correspondiente y enviar la respuesta de regreso al usuario en caso de ser necesario

En palabras más simples , el patrón MVC nos permite separar la lógica de negocio en bloques de código independientes para poder reusarla en peticiones que la necesitan.

¿Cómo adaptarlo a tecnologías modernas?

Hoy en día existen frameworks de frontend como React js y Vue js que se especializan en la creación de interfaces gráficas dinámicas y escalables. Teniendo esto en mente, estos frameworks se encargan de la porción 'Vista' del patrón MVC. Este artículo está enfocado en cómo implementar controladores y modelos en un servidor que aloja un API RESTful.

Separación de funciones

Para implementar el patrón Modelo Controlador necesitamos entender el flujo de información. Vamos a simplificarlo con un ejemplo:

  1. Un usuario inicia sesión en nuestra app.
  2. Después de ingresar su usuario y contraseña, hace clic en el botón de 'Iniciar sesión' que detona una petición el endpoint /login.
  3. El servidor recibe la petición en la ruta /login y la dirige al controlador 'loginController'.
  4. El controlador inspecciona la petición y se da cuenta que contiene dos campos (usuario y contraseña).
  5. El controlador manda a llamar al modelo 'loginModel' y le envía los datos que recibió en la petición.
  6. El modelo recibe la petición y detona la lógica de negocio para que un usuario pueda iniciar sesión.
  7. La lógica de negocio revisa la base de datos para comprobar que el usuario existe y que la contraseña es correcta.
  8. Si el usuario existe y la contraseña es correcta el modelo le devuelve al controlador el acceso correcto. Si el usuario no existe el modelo devuelve al controlador una respuesta en la que le indica que no encontró al usuario. Si la contraseña es incorrecta el modelo le devuelve al controlador una respuesta en la que le indica que la contraseña no es correcta.
  9. Cuando el controlador recibe una respuesta del modelo, la empaqueta y la envía de regreso al usuario.
  10. El código de frontend recibe la respuesta enviada y decide que hacer dependiendo de lo que haya regresado del servidor. Si el servidor envió un token válido, le da acceso al usuario a la app. Se el servidor envió que el usuario no existe, redirecciona a la página de 'Crear una cuenta'. Si el servidor envió que la contraseña es incorrecta, muestra al usuario un mensaje para que lo intente de nuevo.

¿Cómo implementarlo en Express js y Postgres?

Vamos a implementar este patrón en Express js y una base de datos Postgres paso a paso con el ejemplo anterior: (los comandos de la terminal están pensados para Mac OS)

  1. Creamos la carpeta para nuestro servidor y navegamos a ella.

mkdir server && cd server
  1. Creamos los archivos y carpetas que vamos a necesitar para nuestro servidor (local)

mkdir models controllers && touch router.js index.js
cd models && touch loginModel.js index.js && cd ..
cd controllers && touch loginController.js && cd ..

En este momento tenemos 5 archivos

a. El archivo en el que vamos a levantar nuestro servidor con Express js (index.js)

b. El archivo donde vamos a declarar las rutas de nuestra API (router.js)

c. El archivo donde van a ir las funciones de nuestro controlador de login (controllers/loginController.js)

d. El archivo donde van a ir las funciones de nuestro modelo de login (models/loginModel.js)

e. El archivo con la configuración de la base de datos postgres (models/index.js)

  1. Inicializamos el proyecto con NPM

npm init -y
  1. Instalamos las dependencias que vamos a necesitar

npm i express pg
  1. Archivo de servidor

// index.js
const express = require("express");
const app = express();
const PORT = 3000;
const router = require("./router");

app.use(express.json());

app.use(router);

app.listen(PORT, () => {
  console.log(`Servidor corriendo en el puerto ${PORT}...`);
});
  1. Archivo de rutas

// router.js
const router = require("express").Router();
const login = require("./controllers/loginController");

router.post("/login", login.login);

module.exports = router;
  1. Archivo del controlador

// controllers/loginContorller.js
const loginModel = require("../models/loginModel");

exports.login = async (req, res) => {
  try {
    const { username, password } = req.body;
    const loginCheck = await loginModel.checkLogin(username, password);
    let response;
    let status;
    if (loginCheck == "Usuario no existe") {
      response = { status: loginCheck };
      status = 404;
    } else if (loginCheck == "Contreseña incorrecta") {
      response = { status: loginCheck };
      status = 403;
    } else if (loginCheck) {
      response = loginCheck;
      status = 200;
    }
    res.status(status).send(response);
  } catch (error) {
    res.status(500).send({ status: error });
  }
};
  1. Archivo de configuración de la base de datos

// models/index.js
const { Pool } = require("pg");

const pool = new Pool({
  user: "miusuario",
  host: "localhost",
  database: "app",
  password: "micontraseña",
  port: 5432,
});

module.exports = pool;
  1. Archivo del modelo

    El código asume que ya tienes una base de datos postgres creada, si ese no es tu caso ve a la documentación para obtener más información

// models/loginModel.js
const pool = require("./index");

exports.checkLogin = async (username, password) => {
  const user = await pool.query(
    `SELECT * FROM users WHERE username='${username}'`
  );

  const passwordIsCorrect = await checkPassword(username, password);
  if (user.rows.length <= 0) {
    return "Usuario no existe";
  }
  if (user && !passwordIsCorrect) {
    return "Contreseña incorrecta";
  }
  if (user && passwordIsCorrect) {
    const access_token = generateAuthToken();
    return { access_token };
  }
};

const checkPassword = async (username, password) => {
  // Lógica para revisar que la contraseña es correcta
  return Boolean;
};

const generateAuthToken = () => {
  // Lógica para generar un tokende acceso
  return String;
};
  1. Levantar el servidor

node index.js

Ayúdame a mejorar este artículo

¿Quisieras complementar este artículo o encontraste algún error?¡Excelente! Envíame un correo.

  • seb@sebastianfdz.com