Como criar uma WebApi com NestJS, Prisma e MongoDB

Node.js

Como criar uma WebApi com NestJS, Prisma e MongoDB

Luiz Duarte
Escrito por Luiz Duarte em 13/02/2024
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Não sabe o que é o Prisma? Ou até sabe mas não faz a mínima ideia de como usar? Então este tutorial é pra você.

Recentemente escrevi um tutorial sobre como criar uma WebAPI com NestJS, mas que não envolvia banco de dados. Fizemos tudo de forma extremamente profissional e já pensando em futuramente adicionar o suporte a banco de dados. Pois bem, essa hora chegou.

Neste tutorial vamos refatorar o projeto anterior (que avançamos até a parte 3), que você precisa ter feito para conseguir entender esse (a menos que já possua experiência com NestJS), visando adicionar o suporte a banco de dados MongoDB através do uso de um ORM muito popular chamado Prisma. Se preferir, este tutorial também está disponível com versão SQL.

Em Node.js, um dos ORMs mais populares da atualidade é o Prisma. Um ORM é um framework que lhe permite fazer este mapeamento de schema do banco de dados para o código da sua aplicação, JavaScript no caso do Node.js. O Prisma, segundo o site oficial, é um ORM da próxima geração para Node.js baseado em TypeScript, para não apenas diversos bancos SQL como também para MongoDB. Então mesmo que você não use MongoDB assim como eu, mas usa qualquer um dos bancos suportados pelo Prisma, deve conseguir adaptar este tutorial para sua realidade.

Mas antes de começarmos a “brincar” com o Prisma, você vai precisar de um banco de dados criado, faremos isso a seguir.

#1 – Setup do Ambiente

O primeiro passo quando vamos trabalhar com um projeto envolvendo MongoDB é nos certificar que temos um servidor rodando com um banco de dados à nossa disposição. Caso você não possua nenhum na sua máquina, recomendo o vídeo abaixo onde ensino como baixar e instalar o servidor do MongoDB.

Você também vai precisar do Mongo Shell (mongosh), que você baixa no mesmo site do MongoDB em Products > Tools > Shell. Recomendo a versão em zip, basta extrair na pasta bin do seu MongoDB atual.

Dentro da pasta do seu projeto Node, que aqui chamei de prisma-mongo-example (crie onde você quiser), deve existir uma subpasta de nome “data”, crie ela agora. Nesta pasta vamos armazenar nossos dados do MongoDB.

Pelo prompt de comando, entre na subpasta bin dentro da pasta de instalação do seu MongoDB e digite (no caso de Mac e Linux, coloque um ./ antes do mongod e ajuste o caminho da pasta data de acordo):

Isso irá iniciar o servidor do Mongo em modo de replicat set, algo exigido pelo Prisma. Ele vai ficar dando erro e tentando encontrar os pares dele, mas como não vamos subir, você precisa acessar o mongosh em outro terminal (primeiro comando) e rodar o comando na sequência para dizer que é apenas um nó sozinho (no caso de Mac e Linux, coloque um ./ antes do mongod e ajuste o caminho da pasta data de acordo).

Se tudo der certo, o terminal do servidor de MongoDB vai parar de dar erro agora e ficar aguardando conexões.

Depois nosso próximo passo é ter uma webapi NestJS funcional, para adicionarmos as funcionalidades de banco de dados. Se você não fez o tutorial passado conforme recomendei no início do post, mas já conhece NestJS, apenas crie um novo projeto com um módulo CRUD de users. Abaixo o src/user/user.controller.ts do tutorial passado:

E abaixo o src/user/user.service.ts do tutorial passado:

O src/user/user.module.ts:

E o src/app.module.ts importando ele:

Com essa etapa finalizada, agora é hora de trabalharmos no Prisma.

Livro Node.js

#3 – Configurando o Prisma

Nosso próximo passo é instalar algumas dependências e configurar algumas questões mais gerais do projeto. Vamos começar pelas dependências, precisamos adicionar o pacote do Prisma.

Com o Prisma instalado, podemos rodar o comando abaixo para inicializar ele em nosso projeto.

Isso vai criar um arquivo .env, que dentro deverá ter a seguinte variável contendo a connection string para seu banco de dados. Neste exemplo, o banco é um MongoDB que roda na minha máquina (127.0.0.1), na porta padrão (27017) e cujo nome é usersdb. Não tenho usuário nem senha, obviamente todos esses parâmetros você tem de mudar conforme a sua realidade.

O próximo passo é configurar o provedor de acesso à dados no arquivo prisma/schema.prisma, como abaixo.

Agora que configuramos o Prisma para conhecer onde está nosso banco, é hora de criar o schema da nossa coleção de users, como abaixo (no mesmo schema.prisma):

E por fim, agora você deve rodar o comando abaixo para gerar o Prisma Client.

O Prisma Client é uma API gerada de maneira personalizada para o seu banco de dados e é com ele que vamos usar o Prisma de fato no projeto.

Importante sinalizar que toda vez que você mexer na estrutura do seu schema, você deve fazer um novo generate.

Com isso terminamos a etapa mais inicial de configuração do Prisma, podemos começar a usá-lo agora.

#4 – Service com Prisma

Quando estudamos os fundamentos do NestJS entendemos que cabe aos services a tarefa de processamento das requisições. No nosso caso, estas requisições irão ler ou escrever no banco de dados apenas, o que torna o nosso serviço um cliente focado no uso do Prisma. Sendo assim, o primeiro passo é ir no user.service.ts e ajustar ele para que se torne um serviço do tipo PrismaClient.

A herança de PrismaClient vai nos dar acesso a uma série de funções específicas do Prisma para acesso à dados, que usaremos já nesse primeiro bloco de código. Já a implementação da interface OnModuleInit permite que a gente crie um script que rodará assim que o módulo for iniciado, na inicialização do sistema.

Esse onModuleInit é implementado logo abaixo, em uma função de mesmo nome cuja única função será inicializar uma conexão com nosso banco de dados. Para fazer esta conexão usamos a função $connect disponibilizada pelo PrismaClient pra gente.

Agora é hora de escrevermos nossas funções usando a propriedade de mesmo nome da coleção: this.users, começando pelas leituras.

Ambas são bem semelhantes, com a diferença que a segunda usa um filtro pois queremos apenas um usuário, aquele cujo id seja o passado por parâmetro. Repare que na primeira função usei findMany, pois eram vários usuários a serem encontrados, enquanto que na segunda usei findUnique, pois é apenas um e quero aproveitar o índice da chave primária (maior performance).

Agora vamos escrever as funções de escrita, sendo que só teremos uma função de update desta vez.

Na addUser, usamos a função create que espera uma propriedade data com os dados a serem salvos no banco. Opcionalmente esta função espera uma propriedade select que pode mudar o retorno da mesma (por padrão ela retorna o último inserido).

Na updateUser, usamos a função update, informando no where o filtro para selecionar os registros que serão atualizados, seguido da propriedade data informando os dados que serão atualizados.

E por fim, na deleteUser usamos a função delete, que apenas espera um where com o filtro a ser usado para selecionar os registros a serem excluídos.

Com isso, você tem um exemplo de CRUD completo com Prisma ORM, sendo que não é necessário nenhum ajuste no controller para que funcione com este service. Basta reiniciar seu backend e testar via Postman para conseguir ver que está tudo funcionando.

Que tal colocar autenticação nesse projeto? Ensino como neste outro tutorial.

Ou então escrever testes unitários para ele? Ensino neste outro aqui.

Até a próxima!

Curso Node.js e MongoDB

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

2 Replies to “Como criar uma WebApi com NestJS, Prisma e MongoDB”

Adriano Laureano

(extends PrismaClient implements OnModuleInit)

Estender diretamente o PrismaClient não é aconselhável por algumas razões importantes:

Separação de preocupações: Ao injetar o PrismaClient como uma dependência do serviço, você está seguindo o princípio de separação de preocupações. Isso significa que cada parte do seu aplicativo tem uma responsabilidade clara e não está excessivamente acoplada a outras partes. Se você estender diretamente o PrismaClient em vários lugares do seu código, pode ser mais difícil manter essa separação.

Testabilidade: Ao injetar o PrismaClient como uma dependência, você pode facilmente substituí-lo por um stub ou mock durante os testes. Isso é especialmente útil para testes de unidade, onde você pode simular o comportamento do PrismaClient sem depender de uma conexão real com o banco de dados.

Flexibilidade e manutenção: Ao injetar o PrismaClient, você pode facilmente substituí-lo por uma implementação diferente, se necessário, sem alterar muito o restante do seu código. Isso pode ser útil se você decidir mudar de ORM ou se precisar introduzir outras alterações na camada de acesso a dados.

Evita acoplamento direto: Estender diretamente o PrismaClient cria um acoplamento direto entre o código de negócios e a implementação do ORM. Isso pode tornar seu código mais difícil de entender, manter e escalar, especialmente à medida que seu aplicativo cresce.

Portanto, é recomendável injetar o PrismaClient como uma dependência do serviço, seguindo os princípios de design de software e facilitando a manutenção e a evolução do seu aplicativo.

import { Injectable, OnModuleInit } from ‘@nestjs/common’;
import { PrismaClient } from ‘@prisma/client’;

@Injectable()
export class UserService implements OnModuleInit {
constructor(private readonly prisma: PrismaClient) {}

async onModuleInit() {
await this.prisma.$connect();
}

async getUsers() {
return this.prisma.user.findMany();
}

async createUser(data: any) {
return this.prisma.user.create({ data });
}
}

Luiz Duarte

Agradeço a contribuição.