NestJS: introdução e aplicação de CRUD usando MongoDB
Tags: mongodb, tutorial, braziliandevs, node
Published: 2022-08-19 15:19:00

Fala, devs! Tudo certo? 

Se você está neste artigo, é porque deseja entender melhor sobre o NestJS e como é possível criar um CRUD, a base para construção de aplicações back-end, utilizando o banco de dados MongoDB. Então, vamos ao que interessa!

## Antes de mais nada, o que é o NestJS?
NestJS é um [framework](https://kodus.io/bibliotecas-frameworks-javacript-mais-utilizados/?ref=g_devto) Open Source em [Node.js](https://kodus.io/nodejs-por-que-esta-tecnologia-esta-crescendo/?ref=g_devto), que trás um modelo de arquitetura que acelera o desenvolvimento de aplicações backend.

Como o próprio site oficial diz:
> “A progressive Node.js framework for building efficient, reliable and scalable server-side applications.”

Com uma arquitetura modular, bem parecida com o Angular ou Spring, quem conhece vai se familiarizar com ele, que usa os recursos mais recentes do JavaScript, oferecendo padrões de design e arquitetura consolidada.

Ah, bem importante: **NestJS é TypeScript**, ok?!

Além de permitir o uso de TypeScript, esta tecnologia oferece uma série de vantagens para aqueles que atuam tanto na programação back-end, como no front-end. Um exemplo disso está na própria organização do seu código, que é bem estruturada e intuitiva, feita através de um model-service-controller, o que facilita a sua utilização.

Mas vamos lá, a ideia aqui, é conhecer este framework, e nada melhor para isso do que vendo ele em ação.

Bom, de início, vamos instalar o NestJS. Para isso, vale ressaltar que é preciso do Node.js e do NPM já instalado.

## Instalando o NestJS
```
nest new nests-start
```
![Instalação do NestJS](https://lh3.googleusercontent.com/E7hTQwHF9DRJdFCf9VF5s5KE5Q3FpTv-3XZi760W_pqOur65BHvgRxJZkvYjS1QK9L8KKQ8yBpFClENZNfG1ce9PqLLlrBjBWq0Xfe73saYW5hWeB_HfE0EdZtd6lp0tGqGZD5s7)
NPM ou Yarn? Eu vou de Yarn, porque estou mais habituado.
![Seleção do yarn ou npm](https://lh4.googleusercontent.com/VQcWxq8_RcOjgAmxF2pbROueuUypyxwQfyKX-Z5wzrwiQlXypJEno_g0DxtdNmPIX1HuU-aMRqfB3j5yJFkfGk9dAwbgzx7GidGHHWRkG8HuIRq4e423iX1G4arnpoWm1mOrpyxa)
Legal, agora temos a estrutura criada e podemos entender o que ela traz. Além disso, precisamos escolher a IDE para seguir com o projeto. Fique a vontade para usar a de sua preferência, eu vou de WebStorm.
![Estrutura do NestJS](https://lh6.googleusercontent.com/2GZ_3iEtKWm2NRjKe13oYfq7tM6PZE9_GYFXUmUfyUBGH-u0DUzIIythtj2pZ2VEW1kB71ng6I93gtFr16OxD4zSbrbMc0V66mWX0IJf27X2TKvv7UPxNirPMWFitiLNNFoHulPN)
Agora vamos entender isso aqui:
Nessa estrutura temos o _main.ts_, que é o ponto de partida da nossa aplicação.
```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT || 3000);
}
bootstrap();
```
O app.module.ts, que é o core da nossa aplicação, onde são registrados todas as nossas configurações e módulos.
```typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```
Aqui começa a ficar interessante! Repare no “@Module”. Sim, usamos Decorators. Os Decorators funcionam mais ou menos como os Annotations no Spring.

Bom, agora com o projeto criado, vamos executá-lo.
```bash
yarn start:dev
```
Veja o Hello World em http://localhost:3000, que é a porta que foi setada no main.ts

Mas vamos ao que interessa, não é mesmo? Vamos ao nosso famoso CRUD de users com mongodb.

## Implementando o CRUD com MongoDB
Primeiro, vamos limpar esta estrutura, apagando os arquivos:
- app.controller.spec.ts; 
- app.controler.ts; 
- app.service.ts. 
Além disso, vamos editar o app.modules.ts, pois ele instanciava o service e o controler que apagamos.
```typescript
import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```
E agora a mágica: 
Usando o CLI do nest, temos um [gerador de CRUD](https://docs.nestjs.com/recipes/crud-generator#crud-generator)
```bash
nest g resource users
```
Este comando não apenas gera todos os blocos de construção NestJS (módulo, serviço, classes de controlador), mas também uma classe de entidade, classes DTO. 

Abaixo, temos o controller gerado para REST API:
```typescript
import { 
  Controller, 
  Get, 
  Post, 
  Body, 
  Patch, 
  Param, 
  Delete 
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

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

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

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(id);
  }
}
```
Vamos editar o nosso app.modules, registrando nosso users. 
```typescript
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [UsersModule],
  controllers: [UsersController],
  providers: [UsersService],
})
export class AppModule {}
```
Vamos começar pelo nosso create-users.dto.ts, usando o código abaixo.
```typescript
export class CreateUserDto {
  email: string;
  name: string;
  password: string;
}
```
Com a criação do extend CreateUserDto, o update-users.dto.ts, então, já está pronto.

Vamos agora para nossa classe de entidade. Para isso, vamos precisar instanciar o mongo, eu vou usar o mongo Atlas, que para um projeto starter, funciona muito bem.

Na documentação do NestJS, mais especificamente na seção TECHNIQUES, temos as instruções para trabalhar com o mongo.

Vamos instalar o mongoose e a tipagem.
```bash
yarn add @nestjs/mongoose mongoose
```
Vamos editar o arquivo /users/entities/user.entity.ts
```typescript
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type UserDocument = User & Document;

@Schema()
export class User {
  @Prop()
  name: string;

  @Prop()
  email: string;

  @Prop()
  password: string;
}

export const UserSchema = SchemaFactory.createForClass(User);
```
Quase tudo pronto, falta agora configurar o acesso ao mongo e os methods no service e os endpoints no controller.

Vamos lá, no users.module.ts, importar a conexão com o mongo.
```typescript
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User, UserSchema } from './entities/user.entity';
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
  ],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}
```
No users.services.ts, editamos os methods create(), findAll(), findOn(), update() e remove() que foram criados pelo CLI.
```typescript
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { User, UserDocument } from './entities/user.entity';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';

@Injectable()
export class UsersService {
  constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {
  }
  create(createUserDto: CreateUserDto) {
    const user = new this.userModel(createUserDto);
    return user.save();
    }

  findAll() {
    return this.userModel.find();
  }

  findOne(id: string) {
    return this.userModel.findById(id);
  }

  update(id: string, updateUserDto: UpdateUserDto) {
    return this.userModel
      .findByIdAndUpdate(
        {
          _id: id,
        },
        {
          $set: updateUserDto,
        },
        {
          new: true,
        },
      )
      .exec();
  }

  remove(id: string) {
    return this.userModel.deleteOne({ _id: id }).exec();
  }
}
```
O Controller já está pronto, só precisamos editar, pois o type do nosso id é string e não number.
```typescript
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

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

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

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(id);
  }
}
```
Criamos também um arquivo .env na raiz do projeto, setando uma variável com a string de conexão com o seu mongodb.
```
MONGODB = 'mongodb+srv://nestjs:nestjs@clusteralexmaxdev.ex4ok.mongodb.net/test'
```
E tudo pronto, estamos **ON FIRE**.
![Resposta em json](https://lh5.googleusercontent.com/f0D2oc602KIBXZjqOxPY47OeFDWebKiTVJJP2gw6CQQ607bcma4-MCboCGS_zZNOfXUPora1h_GbJtML2BT2Mzfa0vKoD3lAdaksiGJ3QYwRgO6jFNj-3V6z7ABzyoQk_OwueN-J)
A ideia foi apresentar o framework NestJS e mostrar na prática o quão produtivo é desenvolver com este framework.

Se você acompanhou este conteúdo até o final, tenho certeza de que conseguiu desenvolver a sua primeira aplicação de CRUD através do NestJS com MongoDB.

Vale ressaltar que estes conceitos são mais introdutórios e voltarei em outros artigos trazendo um pouco mais sobre este ecossistema do NestJS. (Falando em ecossistema, conheça mais sobre o [ecossistema da Kodus](https://talents.kodus.io/?ref=g_devto)

E, caso queira se aprofundar neste exemplo sobre NestJS, recomendo que você dê uma olhada nesse [repositório no GitHub](https://github.com/alexanderyokogawa/nestjs-api).

Grande abraço e até a próxima.

---
Esse conteúdo é um repost da [Kodus](https://kodus.io/?ref=g_devto) para o membro da nossa comunidade [Alexander Yokogawa](https://www.linkedin.com/in/alexanderyokogawa). Faça parte da comunidade e poste aqui também!