Documentos de Académico
Documentos de Profesional
Documentos de Cultura
además agregaremos código para facilitar temas tan importantes como la validación o la
definición de los datos de los modelos y su correspondencia con el esquema de las tablas de la
base de datos. Dada toda esa funcionalidad que nos queda por agregar, en la práctica no
usaremos interfaces habitualmente, sino clases, ya que necesitaremos aplicar decoradores,
pero su aplicación será similar a lo que hemos visto aquí.
En este artículo vamos a ver un ejercicio sobre cómo organizar un controlador y un servicio en
Nest. Será una práctica básica de funcionamiento de lo que sería un CRUD, pero sin
persistencia, ya que el almacenamiento lo vamos a tener en la memoria.
El objetivo de esta práctica es ofrecer una estructura básica de lo que es un controlador con su
servicio en Nest, que nos servirá más adelante para ir mejorando el servicio y controlador y
aplicarle algunas cosas que no vamos a tocar ahora, como es la validación, la persistencia, etc.
No vamos a partir desde cero, dado que a lo largo del Manual de Nest hemos ido construyendo
nuestra práctica actual, según íbamos aprendiendo lo que son los controladores y servicios.
De momento tenemos:
El controlador ProductsController, que hasta ahora tenía solamente la ruta para recibir
todos los productos y para insertar uno.
El servicio ProductsService, que tenía simplemente los métodos de recibir todos los
elementos y modificar uno.
Como decimos, sería ideal haber leído los artículos anteriores del manual para poder entender
todo lo que nos sirve de código base. Además, algunas cosas sobre el código anterior van a
cambiar, así que merece la pena estar atento a los motivos para aprender más cosas sobre
cómo trabajan controladores y servicios.
Servicio completo
Vamos a comenzar viendo el código del servicio, ya que el controlador se apoya en el servicio.
Esta clase contiene una interfaz pública que permite hacer las típicas operaciones de CRUD.
@Injectable()
export class ProductsService {
private products: Product[] = [
{
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',
}
];
getAll(): Product[] {
return this.products;
}
insert(body: any) {
this.products = [
...this.products,
{
id: this.lastId() + 1,
name: body.name,
description: body.description,
}
];
}
Primero señalar de nuevo que nos apoyamos en una interfaz para definir el tipo "Product".
Quiero volver a mencionar que esta interfaz es solo un preludio de lo que son las entidades,
que nos permiten definir mejor los tipos, de cara al almacenamiento en base de datos.
Como no hemos llegado a esa parte, tenemos suficiente de momento con una interfaz, que
nos permite aportar tipos de TypeScript a nuestro código y así obtener mejores ayudas del
editor y la detección temprana de errores.
Recuerda que los servicios son de las estructuras de Nest catalogadas como "Providers" y que
por ello deben ser decoradas con @Injectable(). Todo esto ya lo hemos visto anteriormente.
El servicio tiene una propiedad privada que es el array de productos. Sobre ese array,
almacenado en memoria, es donde vamos a realizar las operaciones siguientes:
El método getAll()
Este método no ha sufrido ningún cambio con respecto a lo que teníamos, simplemente
devuelve el array de productos tal cual.
Este método recibe el identificador que queremos recuperar y lo devuelve. Para encontar algo
en un array usamos el método find() de Javascript.
Aquí es interesante mencionar que no estamos haciendo comprobaciones algunas sobre si ese
elemento que se desea recuperar existe o no. Más adelante abordaremos este tipo de
validaciones, que tendrán que realizarse en el servicio para liberar de trabajo a los
controladores y evitar repetir código cuando varios controladores usen un mismo servicio.
Este método ha cambiado un poco, para adaptarnos a un modo de trabajo más realista. En
realidad ahora lo que estamos recibiendo es el cuerpo de la solicitud, que enviaremos tal cual
desde el controlador.
Podría darse el caso que los datos del body no contengan toda la información necesaria para
crear un producto. Este supuesto no lo estamos validando todavía.
Este método es totalmente nuevo y nos permite actualizar un producto cuyo id se recibe por
parámetro, con respecto a un contenido, que es el mismo body enviado desde el controlador.
En esta acción usamos el método map() de los arrays para construir un array con el contenido
que había antes, pero sustituyendo el producto con el id a actualizar por un nuevo objeto
construido con los datos del body enviado.
Por último, el método delete() nos permite borrar un elemento del array de productos, el
elemento con el id recibido por parámetro.
Para borrar usamos el metodo filter() de los arrays de Javascript, donde nos quedamos con
todos los elementos del array menos con el que tiene el id que queremos borrar.
Luego tenemos también el método privado lastId() que nos devuelve el id del último elemento
del array. Es privado porque en principio solamente lo necesito usar dentro del servicio.
Como hemos señalado este servicio es bastante elemental. Faltarían muchas cosas que ver,
principalmente las validaciones que habrá que hacer en esta misma clase. Más adelante
trabajaremos con ellas.
Controlador de producto
Ahora vamos a ver el controlador, que hará uso de nuestro servicio. El conocimiento necesario
para poder realizarlo lo hemos adquirido a lo largo de los anteriores artículos del manual.
Ahora vamos a incorporar nuevos métodos y algunas diferencias menores en el trabajo de los
que ya teníamos.
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common';
import { Product } from './interfaces/product.interface';
import { ProductsService } from './products.service';
@Get()
getAllProducts(): Product[] {
return this.productsService.getAll();
}
@Get(':id')
find(@Param('id') id: number) {
return this.productsService.getId(id);
}
@Post()
@HttpCode(HttpStatus.NO_CONTENT)
createProduct(
@Body() body,
){
this.productsService.insert(body);
}
@Put(':id')
update(
@Param('id') id: number,
@Body() body,
){
return this.productsService.update(id, body);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
delete(@Param('id') id: number) {
this.productsService.delete(id);
}
El método que realiza gestiona el request tipo POST para la inserción, createProduct(), ahora
simplemente manda el body de la solicitud al servicio, que debería encargarse de procesarla y
hacer la inserción correctamente.
El método delete() que gestiona la ruta para eliminar un producto, delega también en el
servicio, enviando simplemente el identificador del elemento a eliminar.
Conclusión
Más adelante vamos a mejorar el código presente, para ir agregando algunas mejoras
necesarias para hacer una aplicación más robusta, comenzando por la creación de algunas
comprobaciones básicas y tratamiento de errores en el servicio.