# NEST NestJS é um framework para construção de aplicativos web em Node.js. Ele utiliza TypeScript como sua linguagem principal e é baseado no padrão de arquitetura MVC (Model-View-Controller) para organizar e desenvolver aplicações de forma escalável e modular. Em termos simples, NestJS oferece uma estrutura organizada e poderosa para desenvolver aplicações backend com Node.js. Ele facilita a criação de APIs RESTful e aplicações web, fornecendo uma série de recursos como injeção de dependências, módulos, middleware, e suporte para testes automatizados. ## Inicialização - **Instalar o Nest no computador** - **` npm i -g @nestjs/cli`** - **Criar um novo projeto Nest** - **` nest new <nome_do_projeto>`** - **Rodar a aplicação** - **` npm run start`** - **` npm run start:dev`**(atualiza automaticamente enquanto permanece online) - **Criar uma entidade com uma estrutura de arquivos para o funcionamento do código (controller, service etc.)** - **`nest g resource <nome_da_entidade>`** - **Criar um novo Modulo, Controller ou service** - **`nest generate module nome-do-módulo`** - **`nest generate controller nome-do-controlador`** - **`nest generate service nome-do-serviço`** ## Conceitos Fundamentais ### Decorators Os decoradores no NestJS simplificam significativamente a criação e gerenciamento de rotas, manipulação de dados de requisição/resposta e configuração de serviços. Eles permitem uma abordagem modular e declarativa que promove a reutilização de código e a manutenção de aplicações escaláveis e robustas. - Decoradores de Controlador - **@Controller()**: Define uma classe como um controlador. Opcionalmente, pode receber um caminho base para as rotas gerenciadas pelo controlador. - **@Get(), @Post(), @Put(), @Delete(), etc.**: Define manipuladores de rotas HTTP. São usados dentro de uma classe de controlador para mapear métodos para rotas HTTP específicas. - Decoradores de Método - **@Body()**: Extrai o corpo da requisição e o injeta no método do controlador. - **@Param()**: Extrai parâmetros de rota. - **@Query()**: Extrai parâmetros de consulta da URL. - Decoradores de Parâmetro - **@Req()**: Injeta o objeto da requisição no método do controlador. - **@Res()**: Injeta o objeto da resposta no método do controlador. Geralmente usado para manipular respostas diretamente. - Decoradores de Guardas, Interceptores e Filtros - **@UseGuards()**: Aplica guardas de autenticação/autorização a um método ou controlador. - **@UseInterceptors()**: Aplica interceptores a um método ou controlador. - **@UseFilters()**: Aplica filtros de exceção a um método ou controlador. ### Module São a estrutura fundamental usada para organizar o código em segmentos coesos e reutilizáveis. Cada módulo encapsula um conjunto de funcionalidades relacionadas e promove uma organização clara e modular do código, facilitando a manutenção e a escalabilidade da aplicação. Todo módulo no NestJS é uma classe anotada com o decorador **@Module()**. Esse decorador recebe um objeto de configuração que define os componentes que fazem parte do módulo, incluindo: **providers**: Provedores são basicamente serviços ou outras classes que possuem a lógica de negócios. Eles são anotados com o decorador @Injectable() e podem ser injetados em controladores ou outros provedores. **controllers**: Controladores são responsáveis por manipular as requisições HTTP. Eles são anotados com o decorador @Controller() e definem rotas e métodos HTTP correspondentes. **imports**: Permite que um módulo importe funcionalidades de outros módulos. Isso promove a reutilização e a organização do código em módulos menores e mais coesos. **exports**: Define quais provedores estarão disponíveis para outros módulos que importem este módulo. ```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 {} ``` ### Controller No NestJS, os controladores (controllers) são responsáveis por lidar com as requisições HTTP e retornar respostas aos clientes. Eles são a ponte entre as rotas da aplicação e a lógica de negócios implementada nos serviços. Um controlador é uma classe anotada com o decorador @Controller(), que define um conjunto de rotas e métodos para gerenciar as requisições. ```typescript import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common'; import { UserService } from './user.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; @Controller('users') export class UserController { constructor(private readonly userService: UserService) {} @Post() create(@Body() createUserDto: CreateUserDto) { return this.userService.create(createUserDto); } @Get() findAll() { return this.userService.findAll(); } ... ``` ### Service No NestJS, os serviços (services) são responsáveis por implementar a lógica de negócios da aplicação. Eles são componentes fundamentais que encapsulam as operações e regras de negócio, sendo frequentemente utilizados por controladores (controllers) para manipular dados, interagir com bancos de dados e realizar outras operações necessárias. Um serviço no NestJS é uma classe anotada com o decorador **@Injectable()**. Esse decorador permite que o serviço seja injetado em outros componentes, como controladores ou outros serviços. ```typescript import { Injectable } from '@nestjs/common'; import { CreateUsuarioDto } from './dto/create-usuario.dto'; import { UpdateUsuarioDto } from './dto/update-usuario.dto'; @Injectable() export class UsuarioService { create(createUsuarioDto: CreateUsuarioDto) { return 'This action adds a new usuario'; } findAll() { return `This action returns all usuario`; } ... ``` ### Injeção de Dependências A injeção de dependências (ou DI, do inglês Dependency Injection) é um padrão de design comum usado em desenvolvimento de software, incluindo em frameworks como o NestJS. A ideia central por trás da injeção de dependências é fornecer aos objetos as dependências de que precisam para realizar seu trabalho, em vez de exigir que eles mesmos criem essas dependências. Para entender melhor, considere um cenário em que um objeto A depende de um objeto B para realizar uma determinada funcionalidade. Em vez de o objeto A criar uma instância do objeto B dentro de si mesmo, o que o tornaria fortemente acoplado a B, a injeção de dependências permite que uma instância de B seja passada para A de fora ### Pipes Os pipes no NestJS são uma ferramenta essencial para a transformação e validação de dados. Eles permitem que você defina a lógica de transformação e validação de forma declarativa e reutilizável, melhorando a organização e a robustez da sua aplicação. Com a capacidade de aplicar pipes globalmente, em controladores, métodos ou parâmetros específicos, você tem flexibilidade para usar essa funcionalidade conforme necessário para atender aos requisitos da sua aplicação. - Tipos de Pipes - **Transformation Pipes**: Transformam os dados de entrada para o formato desejado. - **Validation Pipes**: Validam os dados de entrada e podem lançar exceções se os dados forem inválidos. - Pipe Personalizado Um pipe personalizado é uma classe que implementa a interface `PipeTransform` ```typescript import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common'; @Injectable() export class ParseIntPipe implements PipeTransform<string, number> { transform(value: string): number { const val = parseInt(value, 10); if (isNaN(val)) { throw new BadRequestException('Validation failed'); } return val; } } ``` - Aplicação de Pipes Pipes podem ser aplicados de várias maneiras: - **Globalmente**: Aplicados a todos os manipuladores de rota da aplicação. - **Em Controladores**: Aplicados a todos os métodos de um controlador específico. - **Em Métodos**: Aplicados a um método específico de um controlador. - **Em Parâmetros**: Aplicados a um parâmetro específico de um método. ### Interceptors No NestJS, interceptores são uma ferramenta poderosa para modificar a lógica de processamento de solicitações e respostas. Eles permitem que você intercepte as chamadas para manipuladores de rota, adicione lógica personalizada antes ou depois que a solicitação seja processada, e até mesmo modificar as respostas antes de serem enviadas ao cliente. **Funções dos Interceptores** * Transformação de Dados: Modificar a resposta ou a solicitação. * Manipulação de Erros: Capturar e tratar exceções antes que elas sejam enviadas ao cliente. * Logger/Auditoria: Logar informações sobre a requisição e a resposta. * Cache: Implementar lógica de cache. **Criação de um Interceptor** Um interceptor é uma classe que implementa a interface NestInterceptor e o método intercept. Este método recebe dois parâmetros: * **context**: Um objeto que fornece informações sobre a execução atual. * **next**: Um CallHandler que permite continuar a execução da cadeia de interceptores e finalmente invocar o manipulador de rota. ```typescript import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const now = Date.now(); return next .handle() .pipe( tap(() => console.log(`After... ${Date.now() - now}ms`)), ); } } ``` **Aplicação de Interceptores** Interceptores podem ser aplicados de várias maneiras: * **Globalmente**: Aplicados a todas as rotas da aplicação. ```typescript import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { LoggingInterceptor } from './logging.interceptor'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalInterceptors(new LoggingInterceptor()); await app.listen(3000); } bootstrap(); ``` * **Em Controladores**: Aplicados a todas as rotas de um controlador específico. ```typescript import { Controller, Get, UseInterceptors } from '@nestjs/common'; import { LoggingInterceptor } from './logging.interceptor'; @Controller('users') @UseInterceptors(LoggingInterceptor) export class UserController { @Get() findAll() { return 'This action returns all users'; } } ``` * **Em Métodos**: Aplicados a um método específico de um controlador. ```typescript import { Controller, Get, UseInterceptors } from '@nestjs/common'; import { LoggingInterceptor } from './logging.interceptor'; @Controller('users') export class UserController { @Get() @UseInterceptors(LoggingInterceptor) findAll() { return 'This action returns all users'; } } ``` Alguns exemplos de Uso são: - Logar o tempo de execução de cada requisição. - Transformar a resposta para ter um formato especifico. - Verificar se contém algum atributo e barrar a requisição - Capturar e tratar exceções antes que elas sejam enviadas ao cliente. ### Middlewares Os middlewares no NestJS são funções que são executadas antes que o manipulador de rota seja chamado. Eles são ideais para tarefas que precisam ser executadas para todas ou a maioria das rotas, como autenticação, logging, manipulação de erros, entre outras. **Características dos Middlewares** * Execução Antes dos Controladores: Middlewares são executados antes que os manipuladores de rota (controladores) sejam chamados. * Acesso e Modificação do Objeto de Requisição e Resposta: Middlewares podem acessar e modificar os objetos de requisição (req) e resposta (res). * Encadeamento: Vários middlewares podem ser encadeados para uma mesma rota, executando tarefas em sequência. **Criação de Middlewares** Um middleware básico é uma função que recebe três parâmetros: req, res, e next. ```typescript import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { console.log(`Request... ${req.method} ${req.originalUrl}`); next(); } } ``` Exemplo de uso: ```typescript import { Injectable, NestMiddleware, BadRequestException } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class NoPremiumMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { if (req.body && req.body.premium) { throw new BadRequestException('Premium attribute is not allowed in the request body'); } else { next(); } } } ``` Nesse codigo ele verifica se o atributo premium está no json enviado e barra caso esteja. O proposito é que isso seja alterado somente de outra forma **Aplicação do Middleware** - No Módulo Específico ```typescript import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'; import { LoggerMiddleware } from './logger.middleware'; import { UserModule } from './user/user.module'; @Module({ imports: [UserModule], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .forRoutes('users'); } } ``` - Globalmente ```typescript import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { LoggerMiddleware } from './logger.middleware'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(new LoggerMiddleware().use); await app.listen(3000); } bootstrap(); ``` - Rota específica ```typescript import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'; import { LoggerMiddleware } from './logger.middleware'; import { UserController } from './user/user.controller'; @Module({ controllers: [UserController], }) export class UserModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .forRoutes(UserController); } } ``` ### Guards Os guards no NestJS são uma ferramenta poderosa usada para autenticação e autorização. Eles determinam se uma solicitação pode passar para o manipulador de rota com base em alguma lógica, como a verificação de tokens, permissões de usuário, etc. **Características dos Guards** * Autorização e Autenticação: Usados principalmente para garantir que um usuário tenha permissão para acessar uma rota específica. * Baseados em Funções: Implementados como classes que usam a interface CanActivate. **Criação de Guards** Para criar um guard, devemos implementar a interface **CanActivate**. Essa interface requer um método canActivate que é chamado toda vez que uma solicitação é feita para uma rota decorada com o guard. O método canActivate recebe um argumento ExecutionContext e deve retornar um valor booleano que indica se a rota pode ser acessada. Exemplo: Um guard que permite acesso apenas durante um horário específico. ```typescript import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; @Injectable() export class TimeGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const hour = new Date().getHours(); return hour >= 9 && hour < 17; // Permite acesso apenas entre 9h e 17h } } ``` ### Exceptions No NestJS, exceptions são usadas para lidar com erros de forma organizada e consistente. O framework fornece uma maneira fácil de lançar e capturar exceções, permitindo que você mantenha sua aplicação robusta e suas respostas HTTP bem formatadas. **Classes de Exceção Predefinidas** O NestJS fornece várias classes de exceção que herdam da classe base HttpException. Util para ver a resposta HTTP já com o erro incluso * BadRequestException * UnauthorizedException * NotFoundException * ForbiddenException * InternalServerErrorException Cada uma dessas classes gera uma resposta HTTP correspondente ao seu status code (400, 401, 404, 403, 500, etc.). ```typescript @Controller('users') export class UserController { @Get(':id') findOne(@Param('id') id: string) { const user = this.findUserById(id); // Simulação de busca de usuário if (!user) { throw new NotFoundException(`User with id ${id} not found`); } return user; } ``` ### Param Decorators No NestJS, os decoradores de parâmetros (Params Decorators) são usados para extrair dados específicos da requisição em controladores. Eles fornecem uma maneira fácil e intuitiva de acessar parâmetros de rota, corpo da requisição, cabeçalhos, consultas, e mais, diretamente nos manipuladores de rota. Isso ajuda a manter o código limpo e organizado. **Tipos Comuns de Decoradores de Parâmetros** * **@Param()**: Extrai parâmetros de rota. * **@Query()**: Extrai parâmetros de consulta. * **@Body()**: Extrai o corpo da requisição. * **@Headers()**: Extrai cabeçalhos da requisição. * **@Req()**: Extrai o objeto de requisição. * **@Res()**: Extrai o objeto de resposta. * **@Next()**: Extrai a função next do middleware. * **@Session()**: Acessa a sessão (quando usando sessões de servidor). * **@UploadedFile()** e **@UploadedFiles(**): Manipula arquivos carregados (usado com bibliotecas como Multer). **Criando um Decorador Personalizado para Extrair e Validar um Parâmetro de Rota** decorador personalizado chamado @UserId() que extrai um parâmetro id da rota e verifica se ele é um número válido. ```typescript import { createParamDecorator, ExecutionContext, BadRequestException } from '@nestjs/common'; export const UserId = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); const userId = request.params.id; if (!userId) { throw new BadRequestException('User ID parameter is missing'); } const id = parseInt(userId, 10); if (isNaN(id)) { throw new BadRequestException('User ID must be a number'); } return id; }, ); ``` ```typescript import { Controller, Get } from '@nestjs/common'; import { UserId } from './user-id.decorator'; @Controller('users') export class UserController { @Get(':id') findOne(@UserId() id: number) { return `This action returns a user with id: ${id}`; } } ``` ## Integrações, Técnicas e Conceitos no Nest ### Integração com API PAYPAL https://hackmd.io/oaM1L19yQiaQegMwtYwrrQ ### Salvar Imagens no banco de dados https://hackmd.io/@HKFpK9VZQjaePRn5_izbuA/rJHW3JuY0 # Prisma Prisma é uma ferramenta de banco de dados moderna e de código aberto que simplifica o acesso e manipulação de bancos de dados em aplicativos Node.js, TypeScript e JavaScript. Ele oferece um ORM (Object-Relational Mapping) para interagir com o banco de dados de uma maneira mais amigável e intuitiva, permitindo que os desenvolvedores escrevam consultas em uma linguagem declarativa. * **ORM Declarativo:** O Prisma fornece uma camada de abstração sobre o banco de dados, permitindo que os desenvolvedores interajam com o banco de dados usando uma API de alto nível e uma sintaxe declarativa. * **Gerenciamento de Esquema:** Com o Prisma, você define o esquema do banco de dados usando uma linguagem de modelagem de dados chamada Prisma Schema. Isso inclui a definição de modelos, relacionamentos entre modelos, tipos de dados e configurações do banco de dados. * **Migrações de Banco de Dados:** O Prisma oferece suporte a migrações de banco de dados, permitindo que você versione e aplique alterações no esquema do banco de dados de forma segura e controlada. * **Integração com Diversos Bancos de Dados:** O Prisma suporta vários bancos de dados populares, como PostgreSQL, MySQL e SQLite, permitindo que você escolha a melhor opção para o seu aplicativo. * **Type-Safe Query Builder:** O Prisma fornece um query builder type-safe que permite escrever consultas de banco de dados de forma segura em TypeScript. Isso significa que os erros de digitação e outros erros comuns são capturados durante a compilação, em vez de ocorrerem em tempo de execução. * **Prisma Client:** O Prisma gera automaticamente um cliente de banco de dados TypeScript para seu aplicativo com base no esquema definido. Esse cliente fornece métodos para realizar operações de leitura e gravação no banco de dados de forma simples e segura. ## Inicialização - **Instalar a dependência do Prisma** - **`$ npm install prisma --save-dev`** - **Inicializar o prisma na aplicação** - **`npx prisma init`** - Cria a pasta prisma com o arquivo schema, necessário para a configuração do banco de dados que será utilizado. - É necessário alterar o provider para o banco de dados desejado e que seja suportado pelo prisma. - Também é necessário trocar a url para "file:./dev.db", para criar o caminho que será salvo o arquivo do banco de dados. ![image](https://hackmd.io/_uploads/SkzIonu5T.png) ![image](https://hackmd.io/_uploads/rk4hon_qT.png) - **Criar o generate do Prisma** - Gera e atualiza as configurações necessárias para interagir com o banco de dados - **`npx prisma generate`** - **Realizar o migrate do banco de dados** - Semelhante ao versionamento do Git, sempre que o schema for feito ou atualizado é necessário fazer o migrate, salvando e versionando o banco de dados no formato daquele schema configurado. - **`$ npx prisma migrate dev --<nome_do_migrate>`** - **Visualizar o banco de dados (mysqlite)** - Abre uma página que é possível visualizar e filtrar o banco de dados e seus valores - **`npx prisma studio`** ## Relações entre entidades no schema prisma ### One to one Neste tipo de relação, cada registro de uma entidade está associado a no máximo um registro em outra entidade, e vice-versa. É menos comum do que os outros tipos de relacionamento, mas ainda pode ser útil **Neste exemplo, cada usuário pode ter no máximo um perfil (Profile), e cada perfil está associado a no máximo um usuário.** ```typescript model User { id Int @id @default(autoincrement()) name String profile Profile? } model Profile { id Int @id @default(autoincrement()) bio String? userId Int @unique user User @relation(fields: [userId], references: [id]) } ``` ### One to many Neste tipo de relação, um registro em uma entidade está associado a vários registros em outra entidade, mas cada registro nesta segunda entidade está associado a no máximo um registro na primeira. **Aqui, um usuário (User) pode ter vários posts, mas cada post pertence a apenas um usuário.** ```typescript model User { id Int @id @default(autoincrement()) name String posts Post[] } model Post { id Int @id @default(autoincrement()) title String content String authorId Int author User @relation(fields: [authorId], references: [id]) } ``` ### Many to many: Neste tipo de relação, múltiplos registros em uma entidade estão associados a múltiplos registros em outra entidade. ```typescript model User { id Int @id @default(autoincrement()) name String posts Post[] } model Post { id Int @id @default(autoincrement()) title String content String author User[] } ``` **No caso de relações many to many, é comum termos tabela de associação, uma entidade intermediaria que quebre a relação muito para muitos e torne em um para muitos recebendo uma FK de cada entidade.** No Prisma, para modelar um relacionamento many-to-many com uma entidade intermediária, você pode seguir este exemplo: No exemplo anterior, você pode criar uma terceira entidade chamada UserPost, que servirá como a entidade intermediária. ```typescript model User { id Int @id @default(autoincrement()) name String posts PostUser[] } model Post { id Int @id @default(autoincrement()) title String content String authors PostUser[] } model PostUser { id Int @id @default(autoincrement()) user User @relation(fields: [userId], references: [id]) userId Int post Post @relation(fields: [postId], references: [id]) postId Int } @@id([userId, postId]) ``` **Neste exemplo, a tabela PostUser serve como a entidade intermediária que conecta as entidades User e Post. Ela contém as chaves estrangeiras userId e postId, que se referem aos IDs dos usuários e dos posts, respectivamente.** A anotação **@@id([userId, postId])** define que a combinação dos campos userId e postId deve ser única e serve como a chave primária da tabela de associação UserPost. Isso significa que não pode haver duas linhas na tabela UserPost com a mesma combinação de userId e postId. Isso evita duplicatas e garante que a relação many-to-many seja bem representada. # Passo a Passo ## Instalação e Inicialização Após termos modelado o banco de dados assim como as relações entre as entidades, É hora de codar. ### NEST **Antes de tudo necessários instalar o nodejs no computador:** https://nodejs.org/en - **Instalando o framework nest** - **`npm i -g @nestjs/cli`** - **Criando um novo projeto nest** - **`nest new <nome_do_projeto>`** - **Criando uma estrutura de arquivos para o funcionamento do código (controller, service, dto etc.)** - **`nest g resource <nome_da_entidade>`** Necessario executar esse comando para cada entidade do banco de dados na qual será necessário algum endpoint. - **Rodando a aplicação no servidor local para testar os endpoints** - **`npm run start:dev`** Até aqui temos um api funcional que responde a qualquer endpoint devidamente criado em sua estrutura controller-service. Hora de conectar a algum banco de dados. ### Prisma - **Instalar a dependência do Prisma** - **`$ npm install prisma --save-dev`** - **Inicializar o prisma na aplicação** - **`npx prisma init`** **Após essa etapa teremos o prisma instalando no projeto assim como seu arquivo schema e um .env.** - **É necessário alterar o provider do datasource db para o banco de dados desejado e que seja suportado pelo prisma.** - A url inicialmente estára chamando a variavel de ambiente dentro do .env. Um link genérico para um banco de dados. Lá que deve ser colocado o link do seu banco de dados, porém no caso se for o sqlite basta utilizar o **file:./dev.db** que será sera salvo dentro do repositório. ![image](https://hackmd.io/_uploads/SkzIonu5T.png) ![image](https://hackmd.io/_uploads/rk4hon_qT.png) - **Após isso vamos definir nossos models, a representação de como nossa entidade será estruturada se tratando de atributos e relações** ![image](https://hackmd.io/_uploads/BkRYOdtxC.png) - **Realizar o migrate do banco de dados** - Semelhante ao versionamento do Git, sempre que o schema for feito ou atualizado é necessário fazer o migrate, salvando e versionando o banco de dados no formato daquele schema configurado. - **`$ npx prisma migrate dev --<nome_do_migrate>`** Até aqui temos nossa api e nosso banco de dados criados. Hora de juntar tudo ### Vinculando o Banco de dados Antes de tudo, na arquitetura MVC, de forma simples, os controllers guardam os endpoints. Cada endpoint deve estar chamando alguma função do service, que é onde de fato ocorre a comunicação com o banco criando, retornando e atualizando nossas entidades. - **Instalando e gerando o Prisma Client** - **`npm install @prisma/client`** O Prisma Client é uma biblioteca gerada automaticamente que fornece uma API para interagir com o banco de dados definido no schema. No geral, gerar o Prisma Client fornece uma maneira fácil e tipada de interagir com o banco de dados, simplificando o código. - **Criando o prisma service para estabelecer a conexão com o banco de dados** - **`nest g service prisma`** Dentro do prisma service vamos estar colando o seguinte código que vai estar iniciando a conexão com o banco de dados e sendo chamando posteriormente no service para temos nossas funções CRUD: ```typescript import { Injectable, OnModuleInit } from '@nestjs/common'; import { PrismaClient } from '@prisma/client'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit { async onModuleInit() { await this.$connect(); } } ``` - **Injentando as dependencias do PrismaService em cada arquivo module de entidade criado** ![image](https://hackmd.io/_uploads/B1exnqFxA.png) - **Criando o DTO para criar e atualizar o banco de dados** ![image](https://hackmd.io/_uploads/H13WA5FeA.png) O dto de forma bem básica será um modelo para o json recebido. É onde iremos ter alguns fitros e trasnferir os dados entre diferentes camadas do projeto. Poderiamos utilizar diretamente a forma do nosso model, mas o usuario não precisa enviar um id por exemplo. - **Estruturando nosso service** ![image](https://hackmd.io/_uploads/HJtGaqte0.png) Essa é a forma base do nosso service, temos a instancia do prisma como PrismaService para conseguirmos trabalhar com o nosso banco de dados. Além disso utilizamos o private e readonly como formas de assegurar utilizar essa instancia apenas dentro da classe e sem altera-lá. - **Criando as funções dentro do service** ![image](https://hackmd.io/_uploads/B1rVzjYeC.png) Caso seu dto esteja diferente do schema ele pode acusar esse tipo de erro ![image](https://hackmd.io/_uploads/B1KCxjFgA.png) Ter propriedades a menos não é um problema, basta verificar se os nomes e tipos estão corretos - **Criando as rotas no controller** ![image](https://hackmd.io/_uploads/S1awGjtxR.png) Temos uma rota Post que tem como parametro um body de um json do tipo UsuarioDTo e um Get. Ambos estão chamando métodos do usuarioservice. A partir daqui é possível criar um usuario no banco de dados e ver todo que já estão criados. ### Autenticação com JWT Usando a autenticação através de um token jwt que sera associado ao usuario (email e senha) - **Instalando todas as dependências** - **`npm install --save @nestjs/jwt`** - **`npm install --save @nestjs/passport passport passport-jwt passport-local `** - **`npm install --save @types/passport-jwt @types/passport-local`** - **Criando os arquivos necessários** - module, controller e service auth - Pasta de guards e local-auth.guard - Pasta de strategies e local-strategie ![image](https://hackmd.io/_uploads/S15fusVbR.png) - **Definindo o endpoint login no controller** Endpoint que enviaremos email e senha para autenticação. ![image](https://hackmd.io/_uploads/SJCLosVWA.png) - **Criando o guard LocalAuthGuard** Esse trecho de código define um guard de autenticação local em uma aplicação Nest.js, estendendo a classe AuthGuard do pacote @nestjs/passport. O guard, chamado LocalAuthGuard, utiliza a estratégia de autenticação local ('local') da biblioteca Passport. (Mero Padrão de código) ![image](https://hackmd.io/_uploads/H1FQ3sVW0.png) - **Criando o local-strategie** Nesse trecho de código, temos a estratégia usada para autenticação. No construtor, a estratégia é inicializada com campos de entrada de nome de usuário ('email') e senha ('senha'). O método validate é implementado para realizar a validação do usuário, utilizando a função validateUser do authService para verificar as credenciais do usuário (email e senha) e retornar o resultado da validação. ![image](https://hackmd.io/_uploads/ryS_S2EbA.png) - **Criando o validateUser no authService** Ainda na etapa de middleware, precisamos validar se nosso usuario está cadastrado e se a senha é a correta, para isso criamos a função **validateUser**. ![image](https://hackmd.io/_uploads/ByWO8hNWC.png) - **Criando a função para buscar o usuario no UsuarioService** Função importante para verificar a existência do usuario no sistema, lembrando que o atributo a ser procurado deve ser unico (findUnique) ou utilize outra estrategia como procurar id e email/username juntos. ![image](https://hackmd.io/_uploads/rktGPh4bR.png) - **Criando a função login no AuthService** Após a verificação do Guard, vamos utilizar a função login para criar um token jwt e associá-lo ao nosso usuario. Este trecho de código implementa a função login dentro de um serviço de autenticação em uma aplicação Nest.js. A função recebe um objeto de usuário como parâmetro e cria um payload com o ID e o email do usuário. Em seguida, utiliza o serviço JWT para gerar um token JWT, assinando-o com uma chave secreta definida no ambiente e configurando um tempo de expiração de um dia. Por fim, retorna um objeto contendo o token de acesso (JWT) e as informações do usuário. ![image](https://hackmd.io/_uploads/SkgtYh4bC.png) ### Validação do JWT - Criando o guard JwtAuthGuard - Criando o jwt-strategie - Utilizando algum endpoint e passando o token JWT ### Criptografia