Está en la página 1de 7

Servicios

en aplicaciones Nest

A continuación vamos a hacer una zambullida completa en el mundo de los servicios de Nest,
que centralizan las operaciones para el acceso a los datos, así como implementan la lógica de
negocio. Los servicios son una de las clases tipo Provider que tenemos en NestJS, y como todo
provider son inyectables. Los servicios nos proveen de una capa que descarga de trabajo a los
controladores y a la vez permite reutilizar el código a lo largo de la aplicación. Veremos qué son
los servicios y luego implementaremos servicios y los usaremos desde los controladores.
Iremos ampliando la funcionalidad para proveer de más operaciones de trabajo con datos y
realizaremos el almacenamiento en distintos soportes, como la memoria o las bases de datos.

Servicios en NestJS
Qué son los servicios en Nest. Qué son los providers y cómo se puede inyectar estos tipos de
clase en los controladores. Implementaremos un servicio nuevo, crearemos algunos métodos,
para luego usarlo dentro de un controlador.

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. Mediante los servicios podemos liberar de código a los
controladores y conseguir desacoplar éstos de las tecnologías de almacenamiento de datos que
estemos utilizando.

Los servicios son clases, de programación orientada a objetos, como otros componentes de las
aplicaciones. Son clases clasificadas como "provider", un tipo especial de artefactos dentro del
framework. Por eso es interesante que expliquemos qué es un provider antes de ponernos a ver
código de servicios.

Qué son providers

Los providers son un concepto que se usa en el framework Nest, para englobar a un conjunto

http://desarrolloweb.com/manuales/manual-nestjs Página 41 de 112


diverso de clases o artefactos, entre los que se encuentran los servicios, repositorios, factorías,
etc.

Los providers están preparados para ser inyectados en los controladores de la aplicación, y
otras clases si fuera necesario, a través del sistema de inyección de dependencias que
proporciona Nest. Gracias a la inyección de dependencias es muy sencillo crear y proporcionar
instancias de las clases a los controladores, delegando al propio Nest ese trabajo de instanciar
las clases.

Si quieres conocer de manera general este concepto de inyección, te recomendamos la


lectura del artículo Inyección de dependencias.

Todos los providers que pensamos usar dentro de los módulos se tienen que declarar mediante
el decorador @Module(). Esto no es un problema porque generalmente esta tarea se realizará
automáticamente por el CLI al generar las clases inyectables. En este mismo artículo podrás
aprender a usar el CLI para realizar esta labor y experimentaremos cómo nos ayuda a la hora
de crear las clases tipo provider, en este caso servicios, y cómo el CLI las importa y declara
convenientemente en el módulo.

Pero antes de ponernos a crear nuevos servicios podemos fijarnos que en nuestra aplicación
inicial ya teníamos una declaración de providers en el módulo principal de la aplicación. La
podemos ver en el decorator @Module del archivo app.module.ts.

@Module({
imports: [],
controllers: [AppController, ProductsController],
providers: [AppService],
})

En esa declaración de "providers" tenemos un array donde encontramos el servicio usado para
el ejemplo del "Hola Mundo".

Servicios en Nest

Ahora que tenemos claro qué son los providers y sabemos que los servicios son clases incluidas
dentro del conjunto de providers, vamos a profundizar un poco en el concepto de servicio.

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. Es decir, un
servicio tiene que ofrecer los métodos adecuados para que los controladores puedan realizar
las operaciones necesarias para controlar los datos que necesiten usar.

Aparte de descargar de responsabilidad a los controladores y reducir el acoplamiento con las


tecnologías de datos, gracias a los servicios podemos:

Aislar la lógica de negocio en una clase aparte

http://desarrolloweb.com/manuales/manual-nestjs Página 42 de 112


Reutilizar fácilmente el código de trabajo con los datos a lo largo de varios
controladores

Construir un servicio

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

Recuerda que el CLI tiene algunas abreviaciones que te pueden ahorrar teclear demasiado, de
modo que ese comando sería equivalente a escribir:

nest g s products

Una vez construido nuestro servicio con el comando anterior podemos apreciar que se crearon
los siguientes archivos:

products/products.service.ts para el código de la clase del servicio en sí.


products/products.service.spec.ts para el código de las pruebas unitarias.

Ambos archivos los situaron dentro de la carpeta src, como todo código propio de la
aplicación.

Además también se realizó automáticamente la modificación del archivo app.module.ts, en el


que se introdujo:

El import de este servicio


La declaración del servicio en el array de providers

@Module({
imports: [],
controllers: [AppController, ProductsController],
providers: [AppService, ProductsService],
})

Igualmente a los controladores, si no queremos que se genere el archivo de los test unitarios
podemos escribir:

nest g s products --no-spec

http://desarrolloweb.com/manuales/manual-nestjs Página 43 de 112


Decorador @Injectable

Ahora vamos a prestar atención al código base de un servicio, donde es especialmente


importante el decorador @Injectable.

Este es el código base que nos aparece en el archivo products/products.service.ts:

import { Injectable } from '@nestjs/common';

@Injectable()
export class ProductsService {}

El servicio de momento está vacío de funcionalidad, pero gracias al decorador @Injectable


estamos creando una clase que será capaz de inyectarse en los controladores. Todo servicio
debe tener ese decorador antes de la declaración de la clase que lo implementa, para poder
usar la inyección de dependencias que Nest nos proporciona.

Un detalle importante del sistema de inyección de dependencias para providers es que las
instancias proporcionadas a los controladores son únicas, es decir, existe una misma instancia
del servicio a lo largo de toda la aplicación.

Este hecho de crear una única instancia de una clase responde a un patrón conocido que
tiene el nombre de Singleton. Por tanto, podemos decir técnicamente que los servicios son
objetos Singleton.

Cómo inyectar un servicio en un controlador

Los servicios se envían a los controladores por inyección de dependencias. Para conseguirlo en
el controlador tenemos que hacer dos cosas:

Importar el servicio que queremos usar


Inyectarlo en el constructor de la clase

En el proceso de inyección el propio constructor creará una propiedad dentro de la clase que
contendrá el servicio inyectado. Es decir, asociará el servicio al controlador.

Todo esto lo conseguimos con un código como este:

import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Put, Res } from '@nestjs/common';
import { ProductsService } from './products.service';

@Controller('products')
export class ProductsController {

constructor(private readonly productsService: ProductsService) { }

// …
}

http://desarrolloweb.com/manuales/manual-nestjs Página 44 de 112


Hacemos el import de la clase ProductsService
Creamos un constructor, que no teníamos hasta la fecha en el controlador
ProductsController.
Dentro del constructor realizamos la inyección en los parámetros
La palabra private permite que el objeto inyectado (el singleton de ProductsService) se asocie
al controlador por medio de una propiedad privada.
La palabra readonly permite asegurarnos que el servicio es de solo lectura. Es decir,
podremos operar con él y pedirle que haga cosas pero no se permitirá sobreescribir esa
propiedad con otros valores.
La palabra productsService (con la primera en minúscula) es el nombre del parámetro, que
también será el nombre de la propiedad creada.
Muy importante, para que funcione la inyección de dependencias, es indicar el nombre
de la clase del objeto que estamos inyectando. Esto lo hacemos declarando el tipo del
servicio que deseamos inyectar, en este caso ProductsService (con la primera en
mayúscula).
Además, también es reseñable que en el constructor no tenemos código alguno, ya que
el propio TypeScript gracias a la declaración private se encargará de generar esa
propiedad privada por nosotros, sin que tengamos que escribir una línea de código.

Ahora ya estamos en disposición de usar este servicio dentro del controlador!

Implementando el servicio

Ahora vamos a ver cómo sería el código para la implantación de un servicio. Vamos a ir poco a
poco, creando un código básico que nos permita hacer alguna cosa inicial, aunque luego, en
futuros artículos, iremos ampliando funcionalidad al servicio y permitiendo el uso de bases de
datos y similares.

Por tanto, en esta fase inicial del servicio vamos a usar la memoria como espacio de
almacenamiento, lo que no es muy práctico porque cada vez que se reinicie la aplicación
perderemos los datos.

import { Injectable } from '@nestjs/common';

@Injectable()
export class ProductsService {
private products = [
{
id: 1,
name: 'Vela aromática',
description: 'Esta vela lanza ricos olores',
},
{
id: 2,
name: 'Marco de fotos pequeño',
description: 'Marco ideal para tus fotos 10x15',
}
];

http://desarrolloweb.com/manuales/manual-nestjs Página 45 de 112


getAll() {
return this.products;
}
insert(product) {
this.products = [
...this.products,
product
];
}
}

En nuestra primera implementación estamos yendo a lo más básico posible. No estamos


aprovechando todavía algunas de las ventajas de TypeScript que nos aporta el tipado, sin
embargo es suficiente para comenzar a ver cómo podría ser un servicio.

Hemos definido una variable privada llamada products. Además la hemos inicializado ya
con un array de dos objetos producto.
Hemos creado un método llamado getAll() que devuelve directamente el array de
productos.
Hemos creado un método llamado insert() que introduce un nuevo producto, recibido por
parámetro, en el array de productos.

Otro detalle importante, que destaca como carencia en este primer servicio sencillo es toda
la falta de lógica de negocio. Los servicios son el lugar ideal para realizar todas las
comprobaciones necesarias antes de realizar las operaciones. Por ejemplo, si me faltan tales
datos para hacer un alta, o si para hacer una modificación requiero tener un usuario con los
permisos adecuados. Poco a poco iremos complicando este código para incorporar este tipo
de comprobaciones necesarias.

Cómo invocar los métodos del servicio desde el controlador

Ahora, para cerrar finalmente el ciclo de esta primera aproximación a los servicios, veremos
cómo usamos este servicio desde el controlador. Básicamente lo que vamos a hacer es invocar
los métodos que nos proporciona el servicio, para implementar las operaciones de listado de
los productos y la inserción de nuevos productos.

import { Body, Controller, Get, HttpCode, Post } from '@nestjs/common';


import { ProductsService } from './products.service';

@Controller('products')
export class ProductsController {

constructor(private readonly productsService: ProductsService) { }

@Get()
getAllProducts() {
return this.productsService.getAll();
}

@Post()
@HttpCode(204)
createProduct(

http://desarrolloweb.com/manuales/manual-nestjs Página 46 de 112


@Body('name') name: string,
@Body('description') description: string
){
this.productsService.insert({
id: this.productsService.getAll().length,
name,
description
});
}
}

Dentro del controlador tenemos la propiedad this.productsService que es el singleton del


servicio inyectado.
En el método getAllProducts() del controlador devolvemos directamente los productos del
servicio, que conseguimos con this.productsService.getAll()
En el método createProduct() que es una ruta con el método POST, recibimos los datos del
producto que se desea insertar y los enviamos al servicio con el método
this.productsService.insert().

Eso es todo, ahora puedes probar las rutas de get de todos los productos y del post para crear
un nuevo producto para ver cómo los datos de productos gestionado por el servicio van
aumentando.

Conclusión

En este artículo hemos realizado una bonita introducción de los servicios, componentes
fundamentales de las aplicaciones Nest. Los hemos ubicado dentro de las clases tipo
"providers", o proveedores, entendiendo las consecuencias derivadas, como poder hacer
inyectables estos servicios para un fácil uso dentro de los controladores.

Luego hemos realizado una implantación muy sencilla de un servicio y lo hemos usado dentro
del controlador, inyectándolo en el constructor y posteriormente usándolo en los métodos que
era necesario. Tenemos un API ultra-elemental, con persistencia en memoria, que tiene mucho
por delante para evolucionar, pero que empieza a parecerse a lo que nosotros queremos.

En el siguiente artículo vamos a abordar un tema interesante como es el de las interfaces, que
nos permitirán explorar algo más sobre las ventajas de TypeScript para el desarrollo de
aplicaciones en NestJS.

Este artículo es obra de Miguel Angel Alvarez


Fue publicado / actualizado en 08/12/2021
Disponible online en https://desarrolloweb.com/articulos/servicios-nest

Aplicar tipado con interfaces TypeScript en NestJS


En este artículo vamos a ver la mejora que conseguimos al desarrollar con TypeScript gracias
al tipado que podemos aplicar en los servicios Nest mediante interfaces.

http://desarrolloweb.com/manuales/manual-nestjs Página 47 de 112

También podría gustarte