Los servicios en NestJS son los que suelen tener la lógica del negocio y la conexión con la base de datos.
Qué son los servicios en NestJS
Los servicios son una pieza esencial de las aplicaciones realizadas con el framework NestJS. Están pensados para proporcionar una capa de acceso a los datos que necesitan las aplicaciones para funcionar.
Un servicio tiene la responsabilidad de gestionar el trabajo con los datos de la aplicación, de modo que realiza las operaciones para obtener esos datos, modificarlos, etc.
Primer servicio con NestJS
Para crear un servicio puedes utilizar el comando nest generate service <service-name> o en su forma corta nest g s <service-name>.
Los servicios utilizan el decorador @Injectable() y deben ser importados en los providers del módulo al que pertenecen o tu aplicación no lo reconocerá y tendrás errores al levantar el servidor.
// app.module.tsimport{Module}from'@nestjs/common';import{AppService}from'./app.service';@Module({imports:[],providers:[// Imports de ServiciosAppService],})exportclassAppModule{}
Crea un método en el servicio para cada propósito que necesites. Uno para obtener un producto, otro para obtener un listado de productos. Uno para crear producto, para actualizar, eliminar, etc.
// src/app.module.tsimport{Module}from'@nestjs/common';...import{ProductsService}from'./services/products.service';@Module({imports:[],controllers:[...],providers:[AppService,ProductsService],// 👈 New Service})exportclassAppModule{}
Contribución creada con los aportes de: Kevin Fiorentino y Christian Moreno.
find index te trae el indice donde encuentra lo que sea que estes buscando, si fuese el primer elemento el que buscas tu codigo fallaria porque el indice seria 0
update(id: number,payload: any){const found =this.products.findIndex((item)=> item.id=== id);if(found ===-1)thrownewError('Product not found');this.products[found]={id: id,...payload,};return{Message:'Product updated',Updated:this.products[found],};}
En TypeScript también podemos definir que una propiedad de nuestra entidad sea opcional poniendo un signo de interrogación después del nombre de la propiedad:
En mi caso me gusta manejar este tipos de ID con una librería: nanoid
Instalan la librería
npm i nanoid
Importación
import{ nanoid }from'nanoid';
Uso
const newProduct ={id:nanoid(4),// 4: longitud de caracteres de id...payload,};
No olviden actualizar el entity para que en vez de number sea string
Buen aporte
Los servicios son una pieza esencial de las aplicaciones realizadas con el framework NestJS
<aside>
Están pensados para **proporcionar una capa de acceso a los datos** que necesitan las aplicaciones para funcionar.
</aside>
Un servicio tiene la responsabilidad de gestionar el trabajo con los datos de la aplicación, de modo que realiza las operaciones para obtener esos datos, modificarlos, etc.
Con los servicios podemos:
Aislar la lógica de negocio en una clase aparte
Reutilizar fácilmente el código de trabajo con los datos a lo largo de varios controladores
Para construir un servicio podemos usar el CLI de Nest. Para crear la clase de un servicio lanzamos el siguiente comando:
nest generate service products
nest g s products
Además también realiza automáticamente la modificación del archivo app.module.ts en el que se introdujo
@Injectable
El decorador @injectable permite inyectarse en los controladores, todo servicio debe tener este decorador antes de la declaración de la clase que lo implementa para poder usar la inyección de dependencias:
import{ Injectable } from '@nestjs/common';@Injectable()export class ProductsService {}
Que es mejor una entity en clase ó una interface?
Hola, depende, pero en este curso manejamos lo manejamos como clases, ya que luego las vamos a necesitar para aplicar una técnica llamada DTOs (Data transfer objects)
Si sólo tendrás un objeto al que quieres darle cierto tipado, usa interface. Si vas a crear instancias del modelo, usa clase.
De esa manera lo veo.
Normalmente comienzo declarando una interfaz, a medida que estoy trabajando, hay ocasiones que el mismo requerimiento me pide volverlo clase. Es entonces cuando paso de usar una interfaz a clase.
En angular es muy común tener interfaces en vez de clases, más adelante ayuda el hecho de que esta entidad sea una clase? o también se puede utilizar una interfaz?
Siempre comienza usando lo más simple, una interfaz. A medida que vayas utilizando esa interfaz hay una probabilidad que necesites convertirla a clase. El mismo requerimiento te lo solicitará y es ahí donde ya realmente puedes convertirla a una clase.
Pero la idea es siempre comenzar desde lo más simple.
Hola Daniel, osea que pude haber utilizado una interfaz sin ningun problema no?
que tal.. segun lo que estamos construyendo no logro darme cuenta que patron de arquitectura estamos usando..
nestjs nos guia a usar algun patron de arquitectura en especifico??
NestJs trabaja perfectamente con la arquitectura modular
aqui te dejo la documentación, pero traquilamente la puedes adecuar a tu gusto.
Siguiendo con el esquema que hice en la clase de los controlares, así creo mis servicios:
nest g s modules/brand/services/brand --flat
nest g s modules/category/services/category --flat
nest g s modules/customer/services/customer --flat
nest g s modules/order/services/order --flat
nest g s modules/products/services/products --flat
nest g s modules/user/services/user --flat
A su vez la entidad tambien la creo dentro de una carpeta:
modules/product/entity/product.entity.ts
Me parece buena tu organización, y creo que sería bueno también respetar el uso de singulares y plurales en cada nivel de carpetas
Nico ! Como estas? Te hago una consulta, la forma en la que estás organizando los archivos y carpetas, es una convención propia de Nest? No sería mejor manejarlo como lo maneja Angular? Con "features". Es decir: Una carpeta llamada products y dentro de esa carpeta todos los archivos relacionados a la entidad products. Cada uno de los archivos con su respectivo apellido. products.service, products.controller, products.models, etc...
Si, podrias llevarlo de la misma manera como lo mantenes con angular. Me parece que el profe lo deja asi para hacerlo mas simple.
Depende... cada quien lo puede manejar como guste, te recomiendo le heches un vistazo al tema de arquitecturas, por ejemplo la arquitectura exagonal que se parece mucho a lo que mencionas de Angular. En cuanto a APIs es más común tener una organización de este tipo Controladores, Servicios, Modelos o Entidades, Repositorios o DAO, Configuraciones, Interceptores, es decir todo agrupado por lo que son y no por lo que representan (productos, categorias, etc),
porqeu un entidad en lugar de una interfaz ?
Acá les comparto los métodos creados en el servicio:
findAll():Product[]{returnthis.#products;}findOne(id: number):Product|undefined{returnthis.#products.find((product)=> product.id=== id);}create(payload:Omit<Product,'id'>):Product;create(payload:Omit<Product,'id'>[]):Product[];create(payload:Omit<Product,'id'>|Omit<Product,'id'>[]):Product|Product[]{if(Array.isArray(payload)){constnewProducts:Product[]=[];for(const item of payload){this.#counterId+=1;constnewProduct:Product={...item,id:this.#counterId,};this.#products.push(newProduct); newProducts.push(newProduct);}return newProducts;}else{this.#counterId+=1;constnewProduct:Product={...payload,id:this.#counterId,};this.#products.push(newProduct);return newProduct;}}
– @wlensinas, 👀 ojo cuidado al esparcir el payload en un objeto nuevo y dejar cualquier campo que quieras manipular, como el id por encima del spread, al hacer el spread de ...payload luego del id, en este caso si el payload llega con un id no se vera afectado por la declaración del id correspondiente en el nuevo objeto.
Este fue mi acercamiento a el reto planteado por @NicolasMolina:
delete(id: number):Product[]|undefined{const index =this.#products.findIndex(product=> product.id=== id);if(index ===-1){thrownewNotFoundException(`Product with id ${id} not found`);}this.#products.splice(index,1);returnthis.#products;}update(payload:Product,id: number):Product|undefined{const index =this.#products.findIndex(product=> product.id=== id);if(index ===-1){thrownewNotFoundException(`Product with id ${id} not found`);}const updatedProduct ={...payload,id: id
};this.#products[index]= updatedProduct;return updatedProduct;}``` 
buen momento para usar las interfaces creo
Estos son mis métodos para actualizar y borrar productos en memoria:
update(id: number,changes: any){const index =this.products.findIndex((item)=> item.id=== id);const product =this.products[index];this.products[index]={...product,...changes,};}delete(id: number){const index =this.products.findIndex((item)=> item.id=== id);this.products.splice(index,1);return{ id };}
Ok...esto es Angular...que bien!!!
Yo normalmente utilizo interfaces para representar una entidad, no clases.
Sí hay una forma de generar entidades por el cli de nest.