Separación de controladores y servicios en Node.js

Clase 22 de 30Curso de Backend con ExpressJS

Resumen

Al desarrollar aplicaciones con Node.js, es clave separar claramente la lógica de negocio de la estructura de tu backend. Este enfoque facilita la escalabilidad y mantenimiento al permitir identificar rápidamente cada parte del código siempre que necesitas realizar ajustes o solucionar problemas. Para esto, es necesario dividir la aplicación en componentes claros y específicos, tales como controladores y servicios.

¿Por qué separar el controlador y el servicio en tu proyecto?

La lógica del controlador se enfoca en la recepción de datos, gestión de errores y la respuesta final al usuario, mientras que los servicios manejan estrictamente las operaciones relacionadas al negocio, como crear usuarios o manipular bases de datos.

Dividir estas responsabilidades permite:

  • Identificar rápidamente dónde se encuentra un problema específico y solucionarlo sin afectar otras partes del sistema.
  • Tener una estructura clara y mantenible, facilitando la incorporación de nueva lógica o funcionalidades.

¿Cómo estructurar un controlador en Node.js?

El controlador recibe datos desde una ruta, por ejemplo register o login, y gestiona la solicitud que hará al servicio para luego retornar una respuesta adecuada al cliente. Su estructura básica puede incluir:

  • Manejo asincrónico con async/await.
  • Uso de bloques try/catch para gestionar errores claramente.

Por ejemplo, un controlador para registro podría verse así:

const register = async (req, res) => {
  try {
    const { email, password, name } = req.body;
    await registerUser(email, password, name);
    return res.status(201).json({ message: 'User registered successfully' });
  } catch (error) {
    return res.status(400).json({ error: error.message });
  }
};

¿Qué implementaciones incluye un servicio en Node.js?

El servicio maneja específicamente la interacción con tu base de datos y la lógica específica del negocio. Ahí incluirás:

  • El manejo seguro de contraseñas con herramientas como bcrypt.
  • Creación y obtención de usuarios a través de bases de datos como Prisma.
  • Generación de tokens seguros mediante JSON Web Tokens (JWT).

Por ejemplo:

const registerUser = async (email, password, name) => {
  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = await prisma.user.create({
    data: { email, password: hashedPassword, name, role: 'user' }
  });
  return newUser;
};

¿Cuáles características principales manejan los tokens JWT?

Cuando un usuario inicia sesión, es importante validar credenciales, generar tokens y manejar errores cuidadosamente para evitar dar pistas sobre la existencia o no de ciertos usuarios.

  • Un usuario debería recibir un token válido que luego podrá usar para acceder a rutas seguras.
  • Los errores deben manejarse genéricamente para no revelar información sensible.

La creación de tokens JWT podría verse de esta manera:

const token = jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '4h' });

¿Qué debes verificar cuando reestructuras un proyecto Node.js?

Al reorganizar tus archivos, especialmente si mueves carpetas existentes, verifica lo siguiente:

  • Revisa que las nuevas rutas a los archivos sean correctas.
  • Asegúrate que todas las importaciones sean adecuadas para prevenir fallas en ejecuciones.

Revisar rutas:

const authService = require('../services/authService');

Validar mediante mensajes de consola al levantar el servidor:

npm run dev

Esta comprobación rápida puede ahorrarte tiempo identificando errores simples de configuración o rutas incorrectas.

Comparte en los comentarios tu experiencia implementando esta estructura en tus proyectos con Node.js y cuéntanos cualquier duda o sugerencia que tengas sobre buenas prácticas en desarrollo backend.