0% encontró este documento útil (0 votos)
128 vistas

Api Rest NestJS Mongodb

Cargado por

cmasarmijo
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
128 vistas

Api Rest NestJS Mongodb

Cargado por

cmasarmijo
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 34

Creación de una API REST con NestJs y MongoDB

© 2021 Luis José Sánchez.

Todos los derechos reservados.

Foto de portada: KatinkavomWolfenmond de Pixabay.

Publicado en Leanpub: https://leanpub.com/apirestnestjsmongodb

1
Índice
1. Introducción

2. ¿Qué es una API REST?

3. Insomnia

4. NestJs

5. MongoDB

6. Desarrollo de la API

Paso 1 - Creación del proyecto


Paso 2 - Recurso CRUD
Paso 3 - Instalación de Mongoose
Paso 4 - Definición del esquema
Paso 5 - Adaptación del servicio

7. Ejercicios propuestos

8. Soluciones a los ejercicios

9. Otros libros del autor

10. Datos de contacto

2
Introducción
En este breve manual se describe cómo desarrollar una API REST muy simple usando NestJs y MongoDB en
cinco sencillos pasos, creando los endpoints (puntos de acceso a la API) necesarios para obtener, añadir,
borrar y modificar elementos.

Se toma como ejemplo el sujeto tarea. Cada una de las tareas tiene un título, una descripción y, además,
guarda información sobre si está o no está hecha. A continuación se muestra una tarea de ejemplo en
formato JSON:

{
"title": "Comprar pan",
"description": "Comprar pan de molde integral multicereales.",
"done" : false,
}

Además de esta información, cuando una tarea se guarda en la base de datos, se le asigna de forma
automática un identificador único.

El código completo del proyecto desarrollado en este manual está en


https://github.com/LuisJoseSanchez/tasks-api.

3
¿Qué es una API REST?
Las siglas API vienen de Application Programming Interface que se puede traducir al español como Interfaz
de programación de aplicaciones.

En pocas palabras, se puede decir que una API es un software que hace de intermediario o puente para que
dos aplicaciones (o dos partes de una misma aplicación) se puedan comunicar. Es típico tener una API que
permite comunicar el front-end con el back-end.

Las siglas REST vienen de Representational State Transfer y denotan el tipo de API. La característica más
destacable de las API REST es la flexibilidad en cuanto al formato de los datos que se transfieren, que
puede ser XML, JSON, YAML o cualquier otro.

FRONT-END BACK-END
PETICIONES A LA API

RESPUESTAS DE LA API API

Con un ejemplo lo veremos más claro. Imaginemos que desde el front-end se quiere sacar un listado de
todas las tareas (tasks). El procedimiento a seguir, a grandes rasgos, sería el siguiente:

1. Desde el front-end se hace una petición HTTP al endpoint tasks (la URL completa sería algo como
http://myapplication.com/tasks/) de la API.
2. El back-end devuelve un array con todas las tareas en formato JSON (o en cualquier otro formato)
junto con el código 200 que indica que todo ha ido bien y no se ha producido ningún error.
3. El front-end toma ese array y muestra el contenido por pantalla convenientemente maquetado.

4
Insomnia
Insomnia es un programa que permite hacer peticiones HTTP sin necesidad de programar un front-end y es
muy útil para hacer pruebas cuando se está desarrollando una API.

Puede que el lector conozca Postman, que es seguramente el programa más popular de este tipo. En el
presente manual hemos elegido Insomnia por su sencillez.

Esta aplicación se puede descargar de forma gratuita desde https://insomnia.rest

5
NestJs
Según la descripción que encabeza la web oficial, NestJs (o simplemente Nest) es un framework basado en
Node.js para crear aplicaciones del lado del servidor eficientes, fiables y escalables.

Para instalar Nest, hay que teclear lo siguiente en una ventana de terminal:

sudo npm i -g @nestjs/cli

La documentación de Nest es excelente y está disponible en https://docs.nestjs.com

6
MongoDB
MongoDB es una base de datos noSQL, distribuida y está basada en documentos. Encaja muy bien en
aplicaciones en las que se usa como lenguaje javascript o typescript ya que el formato de los datos que se
guardan en esta base de datos es JSON.

Existe una versión gratuita que se puede instalar de forma local llamada Community Server y una versión
en la nube denominada Atlas.

La web oficial es https://www.mongodb.com/es

7
Desarrollo de la API
Paso 1 - Creación del proyecto
Nest permite hacer scaffolding, es decir, crear código mediante comandos. Para ello se utiliza el comando
nest seguido de una serie de opciones. Para ver todas las posibilidades que tenemos a golpe de tecla,
podemos ejecutar nest --help.

Creamos un proyecto nuevo con el nombre tasks-api:

nest new tasks-api

Elegimos npm como gestor de proyectos.

8
Una vez creado el proyecto, lanzamos el servidor:

cd tasks-api
npm run start:dev

Si todo ha funcionado correctamente, la aplicación debe estar operativa en http://localhost:3000

Paso 2 - Recurso CRUD


Existe un elemento en Nest llamado resource (recurso) que permite automatizar en gran medida la creación
de una API. Aunque se podrían crear las carpetas y los ficheros a mano, vamos a hacer uso de esta potente
característica y vamos a definir el recurso haciendo scaffolding:

nest g resource

9
Le damos como nombre al recurso tasks. Elegimos REST API y decimos que sí (Y) queremos que se
creen los puntos de entrada a la API.

Vemos que dentro de la carpeta src, donde está el código fuente del proyecto, se ha creado otra carpeta
con nombre tasks con el siguiente contenido:

tasks
├── dto
│ ├── create-task.dto.ts
│ └── update-task.dto.ts
├── entities
│ └── task.entity.ts
├── tasks.controller.spec.ts
├── tasks.controller.ts
├── tasks.module.ts
├── tasks.service.spec.ts
└── tasks.service.ts

Sin tocar una línea de código ya se pueden ir probando los endpoints o puntos de entrada a la API que se
han creado por defecto.

Por ejemplo, podemos usar la URL http://localhost:3000/tasks en el navegador:

10
O, mejor aún, podemos probar con Insomnia:

Paso 3 - Instalación de Mongoose


Quizás el lector esté familiarizado con el concepto de ORM (Object Relational Mapping) y conozca
herramientas como Hibernate para Java o Doctrine para PHP. En ambos casos, el ORM permite mapear la
estructura de una base de datos relacional sobre una estructura lógica de entidades, de forma que las
acciones CRUD (Create, Read, Update, Delete) a ejecutar sobre la base de datos física se realizan de forma
indirecta por medio del ORM, sin necesidad de escribir código SQL.

Mongoose es un ODM (Object Data Modeling) para MongoDB. Es el equivalente a un ORM pero sobre una
base de datos noSQL documental. Igual que con un ORM, todas las acciones sobre la base de datos se
realizan de forma indirecta mediante el ODM que es el encargado de ejecutar internamente comandos
nativos de MongoDB.

Siguiendo la documentación de Nest, instalamos Mongoose:

npm install --save @nestjs/mongoose mongoose

Es necesario importar MongooseModule en el fichero app.module.ts:


11
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TasksModule } from './tasks/tasks.module';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
imports: [
TasksModule,
MongooseModule.forRoot('mongodb://localhost/tasksdb')
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Hemos especificado una conexión a una base de datos con nombre tasksdb que todavía no existe. El
propio Mongoose se encargará de crearla cuando sea necesario.

Paso 4 - Definición del esquema


Un esquema es un modelo que define qué datos van a tener los documentos que se van a guardar en la
base de datos y de qué tipo van a ser.

En un modelo relacional, un esquema sería algo así como la definición de una tabla. En MongoDB, en
principio, no hay que declarar la estructura de los documentos ya que se trata, por definición, de una base
de datos desestructurada.

En nuestro caso, como estamos trabajando con Mongoose, cada esquema definido se va a mapear a una
colección de MongoDB y va a definir la estructura de esa colección.

Creamos la carpeta schemas dentro de src (fuera de las carpetas de resources).

Dentro de la carpeta schemas, creamos el archivo task.schema.ts.

La estructura del proyecto quedaría como se muestra a continuación:

src
├── app.controller.spec.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
├── main.ts
├── schemas
│ └── task.schema.ts
└── tasks
├── dto
│ ├── create-task.dto.ts
│ └── update-task.dto.ts
├── entities
12
│ └── task.entity.ts
├── tasks.controller.spec.ts
├── tasks.controller.ts
├── tasks.module.ts
├── tasks.service.spec.ts
└── tasks.service.ts

Copiamos el código que viene en la documentación de Nest y lo adaptamos a nuestro gusto para que en
lugar de representar gatos, represente tareas.

El fichero task.schema.ts quedaría de la siguiente manera:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';


import { Document } from 'mongoose';

export type TaskDocument = Task & Document;

@Schema()
export class Task {
@Prop()
title: string;

@Prop()
description: string;

@Prop()
done: boolean;
}

export const TaskSchema = SchemaFactory.createForClass(Task);

Para que el esquema esté accesible, es necesario importarlo desde el módulo correspondiente.

A continuación se muestra el contenido del fichero tasks.module.ts:

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


import { MongooseModule } from '@nestjs/mongoose';
import { TasksService } from './tasks.service';
import { TasksController } from './tasks.controller';
import { Task, TaskSchema } from 'src/schemas/task.schema';

@Module({
imports: [MongooseModule.forFeature([{ name: Task.name, schema:
TaskSchema }])],
controllers: [TasksController],
providers: [TasksService]
})
export class TasksModule {}

13
Paso 5 - Adaptación del servicio
En este paso, vamos a conseguir que el servicio interactúe con la base de datos. Para ello, deberemos
añadir y modificar algo de código basándonos en la documentación oficial de Nest. Se trata del paso más
largo, aunque nada complicado como podrá comprobar el lector.

Inyectamos el modelo que hemos creado en el servicio (tasks.service.ts). Podemos copiar el


constructor que aparece en la documentación de Nest y adaptarlo a nuestro caso.

El constructor quedaría de la siguiente manera:

constructor(@InjectModel(Task.name) private taskModel: Model<TaskDocument>)


{}

Ahora los métodos create() y findAll() devuelven sendas cadenas de texto. Hay que modificarlos
para que create() añada una nueva tarea a la base de datos y findAll() devuelva una lista con todas
las tareas existentes.

Basándonos nuevamente en la documentación de Nest y adaptándola a nuestro caso, estos métodos


quedarían de la siguiente manera:

async create(createTaskDto: CreateTaskDto): Promise<Task> {


const createdTask = new this.taskModel(createTaskDto);
return createdTask.save();
}

async findAll(): Promise<Task[]> {


return this.taskModel.find().exec();
}

Para saber más sobre los métodos disponibles aplicables a los modelos, se puede consultar la
documentación de Mongoose en la siguiente dirección: https://mongoosejs.com/docs/models.html

A continuación se muestra el contenido completo del fichero tasks.service.ts:

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


import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Task, TaskDocument } from 'src/schemas/task.schema';
import { CreateTaskDto } from './dto/create-task.dto';
import { UpdateTaskDto } from './dto/update-task.dto';

@Injectable()
export class TasksService {
constructor(@InjectModel(Task.name) private taskModel:
Model<TaskDocument>) {}

14
async create(createTaskDto: CreateTaskDto): Promise<Task> {
const createdTask = new this.taskModel(createTaskDto);
return createdTask.save();
}

async findAll(): Promise<Task[]> {


return this.taskModel.find().exec();
}

findOne(id: number) {
return `This action returns a #${id} task`;
}

update(id: number, updateTaskDto: UpdateTaskDto) {


return `This action updates a #${id} task`;
}

remove(id: number) {
return `This action removes a #${id} task`;
}
}

En estos momentos, aunque la API no esté completa, ya se puede ir probando. Vamos a lanzar una petición
POST al servidor con Insomnia. No hay que olvidar que la aplicación debe estar funcionando (se lanza con
npm run start:dev).

Al hacer POST, se debería haber creado una tarea. Lo que sucede es que no hemos dado ningún dato para
esa tarea, ni el título ni la descripción ni la información sobre si está o no realizada ¿se habrá grabado algo?
vamos a averiguarlo.

Entramos en el gestor de bases de datos en consola de MongoDB:

mongo

15
Una vez dentro, comprobamos qué ha sucedido:

> show dbs


admin 0.000GB
config 0.000GB
local 0.000GB
tasksdb 0.000GB
>
> use tasksdb
switched to db tasksdb
>
> show collections
tasks
>
> db.tasks.find()
{ "_id" : ObjectId("60f29944a556a02024cc2636"), "__v" : 0 }

¡Estupendo! Se ha creado una base de datos con nombre tasksdb y dentro de ella hay una colección que
se llama tasks que contiene una tarea aunque, de momento con un identificador como único dato.

Vamos a crear ahora un par de tareas con datos de verdad. En el cuerpo (Body) de la petición POST
enviamos los datos en formato JSON.

Hemos creado la tarea "Comprar pan". Observa que el código devuelto cuando se crea correctamente un
objeto es el 201.

Sigamos creando tareas...

16
Comprobamos que se han insertado correctamente las tareas en la base de datos:

> db.tasks.find().pretty()
{ "_id" : ObjectId("60f29944a556a02024cc2636"), "__v" : 0 }
{
"_id" : ObjectId("60f2a1cba556a02024cc2638"),
"title" : "Comprar pan",
"description" : "Comprar pan de molde integral multicereales.",
"done" : false,
"__v" : 0
}
{
"_id" : ObjectId("60f2a237a556a02024cc263a"),
"title" : "Ir al gimnasio",
"description" : "Hacer pecho y bíceps.",
"done" : true,
"__v" : 0
}

¡Perfecto! ¡Ahí las tenemos!

Además del método create(), tenemos implementado en el servicio el método findAll(). Este último
método sirve para obtener todas las tareas. Lo podemos probar haciendo una petición GET.

17
En efecto, al realizar una petición GET en la URL http://localhost:3000/tasks obtenemos un array de todas
las tareas creadas.

El siguiente método que reescribimos en el servicio tasks.service.ts es findOne() que nos


permite obtener una tarea a partir de su id:

async findOne(id: string): Promise<Task>{


return this.taskModel.findById(id);
}

El id en MongoDB puede contener letras y números por lo que debemos hacer un pequeño ajuste en el
método findOne() del controlador tasks.controller.ts para que no se produzcan errores con los
tipos de datos, ya que por defecto, considera los id como números.

@Get(':id')
findOne(@Param('id') id: string) {
return this.tasksService.findOne(id);
}

Probamos haciendo una petición GET a la URL http://localhost:3000/tasks/60f2a1cba556a02024cc2638.


Obviamente, el lector debe cambiar el id por alguno de los que tiene en la base de datos.

18
Por último, reescribimos los métodos update() y remove() del servicio:

async update(id: string, updateTaskDto: UpdateTaskDto): Promise<Task> {


return this.taskModel.findByIdAndUpdate(id, updateTaskDto);
}

async remove(id: string): Promise<Task> {


return this.taskModel.findByIdAndDelete(id);
}

Del mismo modo que hicimos anteriormente, debido a que el id puede contener caracteres, actualizamos
también los dos métodos correspondientes del controlador tasks.controller.ts:

@Patch(':id')
update(@Param('id') id: string, @Body() updateTaskDto: UpdateTaskDto) {
return this.tasksService.update(id, updateTaskDto);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.tasksService.remove(id);
}

Probamos una actualización haciendo una petición PATCH y escribiendo en el cuerpo el atributo que
queremos cambiar en formato JSON. Cambiaremos el valor de description dejando los demás datos
igual:

19
Al mostrar un listado de todas las tareas de la base de datos, vemos que se ha modificado la descripción de
la tarea que queríamos:

> db.tasks.find().pretty()
{ "_id" : ObjectId("60f29944a556a02024cc2636"), "__v" : 0 }
{
"_id" : ObjectId("60f2a1cba556a02024cc2638"),
"title" : "Comprar pan",
"description" : "Comprar pan de centeno.",
"done" : false,
"__v" : 0
}
{
"_id" : ObjectId("60f2a237a556a02024cc263a"),
"title" : "Ir al gimnasio",
"description" : "Hacer pecho y bíceps.",
"done" : true,
"__v" : 0
}

Vamos a borrar esa primera tarea que creamos al principio y que no contenía ningún dato relevante aparte
del id usando una petición HTTP de tipo DELETE:

20
Comprobamos que se ha borrado:

> db.tasks.find().pretty()
{
"_id" : ObjectId("60f2a1cba556a02024cc2638"),
"title" : "Comprar pan",
"description" : "Comprar pan de centeno.",
"done" : false,
"__v" : 0
}
{
"_id" : ObjectId("60f2a237a556a02024cc263a"),
"title" : "Ir al gimnasio",
"description" : "Hacer pecho y bíceps.",
"done" : true,
"__v" : 0
}

Para terminar, se muestra continuación el contenido completo del fichero tasks.service.ts:

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


import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Task, TaskDocument } from 'src/schemas/task.schema';
import { CreateTaskDto } from './dto/create-task.dto';
import { UpdateTaskDto } from './dto/update-task.dto';

@Injectable()
export class TasksService {
constructor(@InjectModel(Task.name) private taskModel:
Model<TaskDocument>) {}

async create(createTaskDto: CreateTaskDto): Promise<Task> {


const createdTask = new this.taskModel(createTaskDto);
return createdTask.save();
}

async findAll(): Promise<Task[]> {


return this.taskModel.find().exec();
}

async findOne(id: string): Promise<Task>{


return this.taskModel.findById(id);
}

async update(id: string, updateTaskDto: UpdateTaskDto): Promise<Task> {


return this.taskModel.findByIdAndUpdate(id, updateTaskDto);
}

async remove(id: string): Promise<Task> {

21
return this.taskModel.findByIdAndDelete(id);
}
}

22
Ejercicios propuestos
Ejercicio 1
Además de los datos title, description y done, ahora cada tarea también debe disponer de
minutes que es el tiempo estimado en minutos que debe tomar la tarea en realizarse. Comprueba que se
pueden crear, borrar y modificar tareas teniendo en cuenta esta mejora.

Ejercicio 2
Implementa dos nuevos endpoints, a saber, tasks/done que devuelve todas las tareas realizadas y
tasks/todo que devuelve todas las que quedan por hacer.

Ejercicio 3
Añade un nuevo endpoint que permita hacer una búsqueda por título, es decir, que sea capaz de obtener
una lista de todas las tareas cuyo título contiene una cadena determinada, sin distinguir mayúsculas y
minúsculas. El formato es tasks/title/(tasktitle). Por ejemplo, tasks/title/pan debería
mostrar las tareas con títulos como "Ir a la panadería", "Comprar pan", "Pan y queso" o "Acampando en el
camping".

Ejercicio 4
Implementa el endpoint tasks/longtasks de forma que devuelva todas las tareas cuyo tiempo
estimado de realización sea mayor o igual a una hora (60 minutos).

23
Soluciones a los ejercicios
Ejercicio 1
Añadir un atributo más a la tarea es tan sencillo como poner una propiedad más en el esquema, tan solo
hay que añadir lo siguiente:

@Prop()
minutes: number;

El fichero task.schema.ts quedaría de la siguiente manera:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';


import { Document } from 'mongoose';

export type TaskDocument = Task & Document;

@Schema()
export class Task {
@Prop()
title: string;

@Prop()
description: string;

@Prop()
done: boolean;

@Prop()
minutes: number;
}

export const TaskSchema = SchemaFactory.createForClass(Task);

Para comprobar que todo sigue funcionando bien, podemos crear una nueva tarea haciendo una petición
POST:

24
Comprobamos que en la base de datos se ha insertado correctamente la tarea con todos los datos, incluido
el tiempo en minutos previsto para su realización:

$ mongo
>
> use tasksdb
switched to db tasksdb
>
> db.tasks.find().pretty()
{
"_id" : ObjectId("60f2a1cba556a02024cc2638"),
"title" : "Comprar pan",
"description" : "Comprar pan de centeno.",
"done" : false,
"__v" : 0
}
{
"_id" : ObjectId("60f2a237a556a02024cc263a"),
"title" : "Ir al gimnasio",
"description" : "Hacer pecho y bíceps.",
"done" : true,
"__v" : 0
}
{
"_id" : ObjectId("60f67d3774a3b822865d9481"),
"title" : "Ordenar escritorio",
"description" : "Poner cada cosa en su sitio.",
"done" : false,
"minutes" : 20,
"__v" : 0
}

Ejercicio 2
Los endpoints que tienen como finalidad obtener elementos (en este caso son tareas) se deben gestionar
mediante peticiones GET.

25
Modificamos el fichero tasks.controller.ts que es el controlador encargado de manejar las
peticiones HTTP añadiendo dos nuevos métodos:

@Get('done')
findDone() {
return this.tasksService.findDone();
}

@Get('todo')
findTodo() {
return this.tasksService.findTodo();
}

Es importante colocar esos dos métodos antes de findAll() que tiene el decorador @Get().

Los métodos findDone() y findTodo() llaman a los métodos homónimos que se encuentran en el
servicio implementado en el fichero tasks.service.ts y que son los encargados de realizar las
consultas con Mongoose para obtener las tareas.

Por tanto, creamos los métodos findDone() y findTodo() en el servicio tasks.service.ts:

async findDone(): Promise<Task[]> {


return this.taskModel.find({"done": true}).exec();
}

async findTodo(): Promise<Task[]> {


return this.taskModel.find({"done": false}).exec();
}

Probamos el endpoint tasks/done para obtener todas las tareas ya realizadas:

Ahora probamos el endpoint tasks/todo para obtener todas las tareas por hacer:

26
Ejercicio 3
Modificamos el controlador tasks.controller.ts añadiendo el método findWithTitle():

@Get('title/:searchString')
findWithTitle(@Param('searchString') searchString: string) {
return this.tasksService.findWithTitle(searchString);
}

Para la búsqueda, hacemos uso de una expresión regular indicando la opción de no distinguir mayúsculas
de minúsculas.

Añadimos findWithTitle() en el servicio tasks.service.ts:

async findWithTitle(searchString: string): Promise<Task[]> {


return this.taskModel.find({"title": { "$regex": searchString,
"$options": "i" }}).exec();
}

Hacemos la prueba pertinente probando la búsqueda de la cadena "ar" en el título de las tareas:

27
Ejercicio 4
Seguimos el mismo procedimiento para añadir el endpoint tasks/longtasks, es decir, primero
añadimos el método en el controlador y luego en el servicio.

Para realizar la comparación "mayor o igual a" se utiliza $gte (greater than or equal).

A continuación se muestra el contenido completo del fichero tasks.controller.ts que incluye el


nuevo endpoint:

import { Controller, Get, Post, Body, Patch, Param, Delete } from


'@nestjs/common';
import { TasksService } from './tasks.service';
import { CreateTaskDto } from './dto/create-task.dto';
import { UpdateTaskDto } from './dto/update-task.dto';

@Controller('tasks')
export class TasksController {
constructor(private readonly tasksService: TasksService) { }

@Post()
create(@Body() createTaskDto: CreateTaskDto) {
return this.tasksService.create(createTaskDto);
}

@Get('done')
findDone() {
return this.tasksService.findDone();
}

@Get('todo')
findTodo() {
return this.tasksService.findTodo();

28
}

@Get('title/:searchString')
findWithTitle(@Param('searchString') searchString: string) {
return this.tasksService.findWithTitle(searchString);
}

@Get('longtasks')
findLongTasks() {
return this.tasksService.findLongTasks();
}

@Get()
findAll() {
return this.tasksService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.tasksService.findOne(id);
}

@Patch(':id')
update(@Param('id') id: string, @Body() updateTaskDto: UpdateTaskDto) {
return this.tasksService.update(id, updateTaskDto);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.tasksService.remove(id);
}
}

A continuación se muestra el contenido completo del fichero tasks.service.ts que incluye el nuevo
método findLongTasks():

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


import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Task, TaskDocument } from 'src/schemas/task.schema';
import { CreateTaskDto } from './dto/create-task.dto';
import { UpdateTaskDto } from './dto/update-task.dto';

@Injectable()
export class TasksService {
constructor(@InjectModel(Task.name) private taskModel:
Model<TaskDocument>) {}

async create(createTaskDto: CreateTaskDto): Promise<Task> {


const createdTask = new this.taskModel(createTaskDto);
return createdTask.save();

29
}

async findAll(): Promise<Task[]> {


return this.taskModel.find().exec();
}

async findOne(id: string): Promise<Task>{


return this.taskModel.findById(id);
}

async findDone(): Promise<Task[]> {


return this.taskModel.find({"done": true}).exec();
}

async findTodo(): Promise<Task[]> {


return this.taskModel.find({"done": false}).exec();
}

async findWithTitle(searchString: string): Promise<Task[]> {


return this.taskModel.find({"title": { "$regex": searchString,
"$options": "i" }}).exec();
}

async findLongTasks(): Promise<Task[]> {


return this.taskModel.find({"minutes": {$gte: 60}}).exec();
}

async update(id: string, updateTaskDto: UpdateTaskDto): Promise<Task> {


return this.taskModel.findByIdAndUpdate(id, updateTaskDto);
}

async remove(id: string): Promise<Task> {


return this.taskModel.findByIdAndDelete(id);
}
}

Hasta el momento no hemos añadido tareas de una hora o más, así que creamos la tarea "Escribir artículo"
con una duración de 120 minutos:

30
Comprobamos que mediante el endpoint tasks/longtasks se muestra la tarea correcta, la que dura 120
minutos y no "Ordenar el escritorio" que tan solo dura 20 minutos.

31
Otros libros del autor
Aprende Java con Ejercicios
"Aprende Java con Ejercicios" es un manual práctico para aprender a programar en Java desde cero. Es un
libro hecho casi a medida de la asignatura Programación que forma parte del currículo del primer curso de
los ciclos formativos DAW (Desarrollo de Aplicaciones Web) y DAM (Desarrollo de Aplicaciones
Multiplataforma) pero igualmente puede ser utilizado por estudiantes de Ingeniería Informática, Ingeniería
de Telecomunicaciones o Ciencias Matemáticas en la asignatura de Programación de los primeros cursos.
Incluye conceptos como variables, tipos de datos, sentencia condicional, bucles, arrays, Programación
Orientada a Objetos, manejo de ficheros, control de excepciones, JSP, acceso a bases de datos desde Java y
mucho más. Contiene más de 300 ejercicios resueltos.

Este libro se puede obtener en el siguiente enlace: https://leanpub.com/aprendejava

Git y GitHub - Guía de Supervivencia


"Git y GitHub - Guía de Supervivencia" es un manual que enseña lo básico para manejar estas dos
herramientas que cualquier programador debería conocer. Esta guía ilustra cómo mantener el código
mínimamente organizado mediante comandos de Git y cómo, además, hacerlo visible a la comunidad de
programadores en el vasto universo de GitHub.

Este libro puede descargarse de forma gratuita desde el siguiente enlace: https://leanpub.com/gitygithub

Apuntes de Javascript - De ES6 a ES10


En "Apuntes de Javascript - De ES6 a ES10" se da un repaso a las principales características de Javascript
desde la versión ES6, liberada en 2015, hasta la versión ES10, que se publicó en 2019. También se incluyen
algunos ejercicios de repaso y sus correspondientes soluciones.

Este libro se puede obtener en el siguiente enlace: https://leanpub.com/apuntesdejavascriptdees6aes10

Aprende Ionic con Ejercicios


"Aprende Ionic con Ejercicios" es un manual práctico para aprender a desarrollar aplicaciones híbridas para
dispositivos móviles con el framework Ionic.

Este libro se puede obtener en el siguiente enlace: https://leanpub.com/aprendeionic

Linux Practical Manual with Exercises


"Linux Practical Manual with Exercises" es un manual de Linux para trabajar utilizando los comandos de
terminal. Contiene cuatro capítulos y más de 70 ejercicios resueltos clasificados por dificultad. Está escrito
en inglés.

Este libro puede descargarse de forma gratuita desde el siguiente enlace:


https://luisjose.com/assets/descargas/linux/linux_practical_manual_31_07_2014_en.pdf

32
Datos de contacto
Puedes ponerte en contacto con Luis José Sánchez mediante LinkedIn
(https://www.linkedin.com/in/luisjosesanchez) y también lo puedes seguir en Twitter (@luisjoseprofe).

33

También podría gustarte