Cuando trabajamos en la creación de aplicaciones, nos encontramos con la necesidad de gestionar la lógica de negocio de manera eficiente. La lógica de negocio es el núcleo de nuestra aplicación, donde encapsulamos todos los casos de uso, gestionamos transacciones y trabajamos con datos. Para lograr esto, utilizamos los servicios, que permiten interactuar con la lógica de manera ordenada. En lugar de mezclar el código de negocio con el routing, separamos estas responsabilidades. Esto se basa en principios como The Clean Architecture y el principio de responsabilidad única.
¿Cómo implementar servicios en nuestra aplicación?
Para llevar la lógica de negocio a los servicios, necesitamos estructurar nuestro código de acuerdo con las capas de la arquitectura limpia. Estos son los pasos básicos para implementar servicios:
Crea una carpeta de servicios: Dentro de tu proyecto, crea una carpeta específica llamada "Services".
Define un servicio base: Con el nombre de "Product.Service.js", que actuará como base para los métodos de productos.
Utiliza una clase para encapsular la lógica: Implementa una clase para definir métodos como crear, buscar, editar, y eliminar.
Manipulación de datos: Inicialmente, los datos pueden manejarse en memoria utilizando un array, y más adelante se pueden conectar a bases de datos como Postgres.
Ejemplo de implementación
classProductService{constructor(){this.products=[];this.generate();}generate(){for(let i =0; i <100; i++){this.products.push({id: faker.datatype.uuid(),name: faker.commerce.productName(),price: faker.commerce.price(),});}}find(){returnthis.products;}findOne(id){returnthis.products.find(item=> item.id=== id);}// Métodos adicionales como crear, editar y eliminar}module.exports=ProductService;
¿Cómo integrar los servicios con el routing?
El routing debería encargarse simplemente del acceso a nuestra API, dejando la lógica de negocio a los servicios. La integración se realiza importando nuestro servicio en el módulo de routing y utilizando sus métodos para gestionar las solicitudes.
Separar la lógica de negocio del routing ofrece múltiples ventajas, entre ellas:
Mantenimiento: Facilita la actualización de código al estar desacoplado.
Reusabilidad: Permite reutilizar la lógica de negocio en diferentes partes de la aplicación.
Evolución del sistema: Facilita el escalamiento del proyecto.
Claridad en el código: Mejora la legibilidad y comprensión del código.
Esta separación nos ayuda a construir aplicaciones más robustas, modulares y alineadas con las mejores prácticas de desarrollo de software.
En resumen, implementar servicios y separar la lógica de negocio del routing es esencial para desarrollar aplicaciones escalables y fáciles de mantener. ¡Continúa explorando esta metodología y aplica estos principios a los demás endpoints de tu aplicación para dominar la estructura de un proyecto profesional!
Les dejo el recurso donde el tío bob la propuso por primera vez:
Les dejo mis apuntes de la clase 🙈
yo tome la decisión a partir de este curso de tomar Mis Apuntes del Curso, denle click por si les sirve :)
haganme Pull request si no están de acuerdo con algo xDDD
Así entendí "clean arquitecture".
Me encantaría leer correcciones.
Me confundo porque las bases de datos según eso van en entidades pero según el que mostró el profesor van en los Frameworks y Drivers
¿que herramienta usas para hacer estos graficos?
Actualmente el módulo random de @faker-js/faker está @deprecated, y se recomienda usar en su lugar:
faker.string.uuid()
para generar un id.
Gracias Jhon Eiber
Muchas gracias
Uff hasta ahora el curso me ha encantado, super claro y bien estructurado. Asi va mi codigo por ahora, me ha parecido muy buena la parte de encapsular el funcionamiento en clases :D
Resumen de la clase:Concepto
Los servicios es donde encapsulamos todos los casos de usos y comenzar a interactuar con la lógica de negocio.
En el caso de una tienda: hacer compras, transacciones, etc.
.
Estructura
Esta arquitectura está definida por capas.
Entidades:
En esta capa encontramos las entidades base del negocio.
En nuestro caso: productos, categorías, órdenes de compra.
Casos de uso
En esta capa tenemos lo relacionado a la lógica de negocio
En esta capa se encuentra los servicios
Controladores
En esta capa se brinda el acceso.
Aquí encontramos el routing
.
Flujo de trabajo:
Controladores: Encontramos los routes y middlewares.
Los controladores acceden a la capa de servicios
Servicios: donde se encuentra la lógica de negocio
Los servicios usan las librerías.
Las librerías se encargan de contactarse a la capa de entidades
Las librerías se contactan a otras fuentes de datos: API externa o base de datos.
Buen resumen, gracias
Muchas gracias !!!
Me está encantando este curso, cómo es que lo explica el profesor.
Incluso me estoy interesando mucho por el mundo del backend. 😁
👀 OJO:
Ya que el profesor menciona mucho el tema de las convenciones a la hora de nombrar las cosas, aqui les dejo esta convención:
Las clases se nombran en singular y usando PascalCase:
Ejemplo: Persona, Producto, Categoria, o en en el caso de esta clase debería ser ProductService.
Las funciones se nombran en verbos (crear, agregar, actualizar, etc) y usando camelCase:
Para la peticion get que busca por id una manera de validar primero si hay algun valor retornado se puede hacer de la siguiente manera:
router.get('/:id',(req, res)=>{const{ id }= req.params;const product = service.findOne(id);if(!product){ res.status(404).json({message:`El producto con id ${id} no existe`});}else{ res.status(200).json({ product
});}});
De esta manera nos aseguramos que traiga valor la consulta de lo contraria manejamos la respuesta que no encontró el objeto buscado.
Este profesor es muy bueno, el tema de los servicios siempre me habían confundido cundo los usábamos en otros cursos de la Escuela de JS.
De una vez agregue una validación si no encuentra el id para retornar un 404 (yo lo estoy haciendo con books en vez de products):
router.get('/:id',(req, res)=>{const{ id }= req.params;const book = service.findOne(id);if( book ){ res.status(200).json({message:"Libro encontrado", book
})}else{ res.status(404).json({message:"Libro no encontrado :( ",})}})
Muy buen aporte! Gracias 🤗
Hasta este punto me siento super bien, con la forma de explicar de este profe, grande Nico!
Cada partecita aislada y bien explicada para no mezclar cosas
Hola, a todos!
A la fecha, 10-01-24 faker funciono de esta forma:
generate(){const limit =100;for(let index =0; index < limit; index++){this.products.push({id: faker.string.uuid(),name: faker.commerce.productName(),price:parseInt(faker.commerce.price(),10),image: faker.image.url(),});};};
Gracias :D
Les comparto mi código con mejoras para realizar un limit
hola, en el servicio de usuarios cada vez que se hace lapeticion y se cambia el limit no se generan nuevos usuarios?
Cual es la diferencia entre controlador y servicios? ya que los dos manejan la parte logica de una aplicacion.
Normalmente, los controladores son una capa que se encarga de administrar el trabajo. En el patrón usado en este curso, ese trabajo es realizado por los router.
Por otro lado, los servicios se encargan de toda la lógica de tu negocio; esto es, todos los algoritmos que hacen el trabajo de hacer las operaciones definidas (agregar un usuario, agregar un producto, buscar un producto). Esto se hace para desacoplar los componentes y si necesitas hacer cambios sea más sencillo. Puedes encontrar más información aquí:
Me di una pausa en esta parte del curso y me pregunto porque la carpetas routes y services no estan dentro de una carpeta src o app, no seria una mejor practica?
En las versiones modernas de @faker-js/faker, la función para generar UUID cambió de faker.datatype.uuid() a faker.string.uuid(). Si usas la versión 9.x.x o superior, debes actualizar tu código para evitar errores.
Para los que estan viendo la clase en tiempos recientes, los uuid de faker ahora se encuentran en string, asi que usen:
faker.string.uuid()
Porque no se usa import en lugar de require?
En Node no es válido usar import, si no me equivoco es porque Node usa ES5 🤔.
Porque import no está completamente soportado por Node.js todavía. Sin embargo, puedes usarlo haciendo algunos ajustes. Si quieres aprender como hacerlo esta clase te puede ser útil. Este enlace también te puede ser bastante útil.