Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
Atlaschevron-right

Crie uma API CRUD com MongoDB, Typescript, Express, Prisma e Zod

Onyedikachi Kindness Eni9 min read • Published Sep 04, 2024 • Updated Sep 04, 2024
PrismaTypeScriptAtlas
APLICATIVO COMPLETO
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Visão geral do projeto

As tecnologias tradicionais geralmente têm dificuldades para acompanhar as demandas de escalabilidade, manutenção e ciclos rápidos de desenvolvimento. Esses sistemas são atormentados por arquiteturas monolíticas, bases de código difíceis de manter e falta de ferramentas modernas, o que gera ineficiências e aumenta os custos de desenvolvimento.
Entre na pilha moderna: TypeScript, Express, Prisma, MongoDB e Zod. Esta combinação poderosa oferece uma solução robusta, segura para tipos e escalável para a construção de aplicativos da web. O TypeScript aprimora o JavaScript com tipagem estática, reduzindo erros de tempo de execução e melhorando a produtividade do desenvolvedor. Express, uma estrutura da web minimalista, simplifica a criação de APIs com seus recursos de roteamento e middleware leves, mas poderosos. Prisma, um ORM de última geração, fornece uma interface de tipo seguro para interagir com bancos de dados, preenchendo a lacuna entre a lógica do aplicativo e as operações do banco de dados. MongoDB Atlas, um banco de dados e plataforma de dados NoSQL líder, se destaca no tratamento de grandes volumes de dados não estruturados e dimensionamento horizontal. Por fim, o Zod garante a integridade dos dados com sua declaração e validação de esquema TypeScript.
Usando essa pilha moderna, criaremos uma API básica de gerenciamento de usuários que executará as seguintes operações CRUD:
  • Criar contas de usuário
  • Ler perfis de usuário
  • Atualizar informações do usuário
  • Excluir contas de usuário
O Express será usado para construir o servidor web, Prisma o ORM, MongoDB como banco de dados e MongoDB para validar as cargas úteis.

Pré-requisitos

  • Conhecimento prático do Typescript
  • Familiaridade com o Express
  • MongoDB Atlas cluster
  • Editor de código — como o VS Code
  • Node.js LTS mais recente instalado no seu computador
O código fonte deste projeto pode ser encontrado no GitHub.

Configuração do projeto

Instalando dependências

Crie um diretório de projeto chamado CRUD-API e navegue até ele.
1mkdir CRUD-API
2cd CRUD-API
Em seguida, inicialize um novo projeto e instale o Typescript e o Prisma:
1npm init -y
2npm install prisma typescript ts-node @types/node --save-dev
O comando anterior cria um arquivopackage.jsoncom uma configuração Typescript:
Em seguida, inicialize o TypeScript:
1 npx tsc --init
Execute o seguinte comando para invocar o Prisma CLI.
1npx prisma
Execute o seguinte comando para configurar seu projeto Prisma ORM:
1npx prisma init
O comando anterior realiza as seguintes ações:
  • Cria um novo diretório Prisma com um arquivo schema.prisma
  • Cria um .env arquivo, onde será definida a variável de ambiente utilizada para a conexão com o banco de dados
Execute o comando a seguir para instalar o pacote @prisma/cliente, o que nos permitirá usar o Prisma Client.
1npm install @prisma/client express zod
No comando anterior, instalamos o pacote@prisma/client , Expresse zod. O pacote@prisma/client nos permitirá usar o Prisma Client para acesso ao banco de dados.
Por fim, execute o seguinte comando:
1npm install @types/express nodemon --save-dev
Depois de instalar as dependências, seu package.json arquivo deve ficar assim:
1{
2 "name": "crud-api",
3 "version": "1.0.0",
4 "description": "",
5 "main": "index.js",
6 "scripts": {
7 "test": "echo \"Error: no test specified\" && exit 1"
8 },
9 "keywords": [],
10 "author": "",
11 "license": "ISC",
12 "devDependencies": {
13 "@types/express": "^4.17.21",
14 "@types/node": "^20.12.10",
15 "nodemon": "^3.1.0",
16 "prisma": "^5.13.0",
17 "ts-node": "^10.9.2",
18 "typescript": "^5.4.5"
19 },
20 "dependencies": {
21 "@prisma/client": "^5.13.0",
22 "express": "^4.19.2",
23 "zod": "^3.23.7"
24 }
25}
A estrutura de árvore do projeto deve ficar assim:
1├── CRUD-API
2│ ├── node_modules
3│ ├── Prisma
4│ │ └── Schema.prisma
5│ ├── src
6│ ├── .gitignore
7│ ├── package.json
8│ ├── package-lock.json
9│ └── tsconfig.json

Configurando o Express

No diretório raiz do projeto, crie um subdiretório src . O diretóriosrc incluirá o código fonte da API.
Em seguida, no diretório src, crie um arquivo app.ts e insira o seguinte código:
1import Express from 'express';
2
3// Initiate express
4const app = Express();
5
6app.use(Express.json());
7
8// Setup “hello world” endpoint
9
10const port = process.env.PORT || 3000;
11
12app.get('*', (req, res) => res.send('Hello World!'));
13
14// Start the express server on the relevant port
15app.listen(port, () => {
16 console.log(`server is running on ${port}`);
17});

Executando o Express

Para iniciar nosso servidor, temos que adicionar um novo script ao nosso arquivo package.json. Adicione a seguinte linha à propriedade scripts do arquivo package.json:
1"dev": "nodemon --watch ./src --ext ts --exec 'ts-node ./src/app.ts'"
No código anterior, estamos usando o comando nodemon. O nodemon é uma ferramenta soberba para aplicativos Node.js. Ele pode reiniciar seu servidor quando a origem muda.
Digite o comando abaixo para iniciar o servidor:
1npm run dev
Agora, quando você for ao seu navegador e inserir http://localhost:3000, você verá o texto Hello World! da nossa função de chamada de resposta Express. HelloWorld HealthCheck

Conexão com o banco de dados (MongoDB)

Para armazenar nossos dados, usaremos MongoDB Atlas. Uma URL de conexão do banco de dados é necessária para conectar o banco de dados via Prisma. Siga o guia para configurar um cluster MongoDB Atlas e obter um URL de conexão.
A seguir, no arquivo.env, adicione o URL de conexão como uma variável de ambiente:
1DATABASE_URL="mongodb+srv://<username>:<password>@<cluster-name>.xxxxx.mongodb.net/"
No arquivoprisma.schema, insira o seguinte código:
1generator client {
2 provider = "prisma-client-js"
3}
4
5datasource db {
6 provider = "mongodb"
7 url = env("DATABASE_URL")
8}
O código anterior fornece os dados necessários para que o Prisma se conecte ao nosso banco de dados. No bloco da fonte de dados, o valor passado para o provedor representa o tipo de banco de dados que está sendo usado (MongoDB, nesse caso), enquanto o valor de URL é a URL de conexão do banco de dados.

Criando o esquema Prisma

Como estamos criando uma API básica de gerenciamento de usuários, apenas uma única collection será necessária.

Modelo do utilizador

O modelo de usuário definirá os detalhes do usuário a serem armazenados no banco de dados, com os seguintes atributos:
  • nome: string, campo necessário para armazenar o nome do usuário
  • e-mail: string, campo obrigatório para armazenar o e-mail do usuário
  • phoneNumber: string, campo obrigatório para armazenar o número de telefone do usuário
  • gênero: string, campo obrigatório para armazenar o gênero do usuário

Pontos de conexão de API para CRUD de usuário

Para habilitar e lidar com as operações CRUD do usuário no banco de dados, implementaremos os seguintes endpoints de API.
1Operation API route HTTP method
2Create User /api/users POST
3Get Users /api/users GET
4Fetch a User /api/users:userId GET
5Update a User/api/users:userId PATCH
6Delete a User/api/users:userId DELETE
Agora, vamos criar o esquema da API.
No arquivo prisma/schema.prisma, adicione o seguinte código:
1model User {
2 id String @id @default(auto()) @map("_id") @db.ObjectId
3 name String
4 email String
5 phoneNumber String
6 gender String
7}
Em um banco de dados relacional tradicional, um modelo criará uma tabela, mas como estamos usando o MongoDB, nosso modelo cria uma collection. Observe que o campo id é mapeado com o gravador @map("_id") porque _id é o padrão fornecido pelo MongoDB.
Agora, vamos gerar o Prisma Client executando o seguinte comando:
1npx prisma generate
O Prisma Client nos dá acesso com segurança de tipo ao nosso banco de dados.
Em seguida, implementaremos nossos comandos de rota que utilizarão o Prisma Client para executar operações no banco de dados.

Controles

Basicamente, os roteadores e controladores permitem o tratamento estruturado de solicitações e respostas em um aplicativo. Os roteadores mapeiam as solicitações HTTP de entrada para endpoints específicos, enquanto os drivers recebem as solicitações dos roteadores, processam qualquer lógica de negócios, interagem com o banco de dados e retornam as respostas apropriadas ao cliente.
Agora, vamos criar as rotas e drivers.
No src diretório, crie um client.ts arquivo e insira o seguinte código:
1import { PrismaClient } from '@prisma/client';
2
3const prisma = new PrismaClient();
4
5export default prisma;
No código anterior, criamos uma instância do Prisma Client, que será usada para interação com o banco de dados.
Em seguida, no diretóriosrc, crie os subdiretórios routes e controllers.
1📦 CRUD-API
2┣ 📂 src
3┃ ┣ 📂 routes
4┃ ┣ 📂 controllers
5┃ ┣ 📄 app.ts
6┃ ┣ 📄 client.ts
Por padrão, um controlador lida com as solicitações recebidas, processa-as e fornece uma resposta apropriada. Vamos implementar os comandos para nossa API.
No subdiretório de comandos, crie um arquivouser.route.ts.

controlador createUser

O createUser lida com solicitações POST para criar novos usuários.
Digite o seguinte código no arquivouser.route.ts.
1import { Request, Response } from "express";
2import prisma from "../client";
3
4// Creating a user
5export async function createUser(req: Request, res: Response) {
6 try {
7 const user = await prisma.user.create({
8 data: req.body,
9 });
10
11 res.status(201).json({
12 status: true,
13 message: "User Successfully Created",
14 data: user,
15 });
16 } catch (error) {
17 res.status(500).json({
18 status: false,
19 message: 'server error'
20 });
21 }
22}

Controlador getUsers

O controlador getUser lida com solicitações GET para todos os usuários.
Digite o seguinte no arquivouser.route.ts.
1// Get all Users
2export async function getUsers(req: Request, res: Response) {
3 const users = await prisma.user.findMany();
4
5 res.json({
6 status: true,
7 message: "Users Successfully fetched",
8 data: users,
9 });
10}
11
12In the preceding code, the getUsers controller gets all users.
13
14### getUser controller
15The getUser controller handles GET requests for a single user.
16
17Enter the following in the `user.route.ts` file.
18// Get a single user
19export async function getUser(req: Request, res: Response) {
20 const { userid } = req.params;
21 const user = await prisma.user.findFirst({
22 where: {
23 id: userid,
24 },
25 });
26
27 res.json({
28 status: true,
29 message: "User Successfully fetched",
30 data: user,
31 });
32}
No código anterior, o controlador getUser obtém um único usuário.

controlador deleteUser

Digite o seguinte no arquivouser.route.ts.
1// deleting a user
2export async function deleteUser(req: Request, res: Response) {
3 const { userid } = req.params;
4
5 try {
6 const user = await prisma.user.findFirst({
7 where: {
8 id: userid,
9 },
10 });
11
12 if (!user) {
13 return res.status(401).json({
14 status: false,
15 message: 'User not found',
16 });
17 }
18 await prisma.user.delete({
19 where: {
20 id: userid,
21 },
22 }),
23 res.json({
24 status: true,
25 message: 'User Successfully deleted',
26 });
27 } catch {
28 res.status(501).json({
29 status: false,
30 message: 'server error',
31 });
32 }
33}
No código anterior, o controlador deleteUser exclui um usuário.

Controlador de atualização do usuário

Digite o seguinte no arquivouser.route.ts.
1// updating a single user
2export async function updateUser(req: Request, res: Response) {
3 try {
4 const { userid } = req.params;
5
6 const user = await prisma.user.findFirst({
7 where: {
8 id: userid,
9 },
10 });
11
12 if (!user) {
13 return res.status(401).json({
14 status: false,
15 message: 'User not found',
16 });
17 }
18
19 const updatedUser = await prisma.user.update({
20 where: {
21 id: userid,
22 },
23 data: req.body,
24 });
25
26 res.json({
27 status: true,
28 message: 'User Successfully updated',
29 data: updatedUser,
30 });
31 } catch (error) {
32 console.log(error);
33 res.status(500).json({
34 status: false,
35 message: 'server error',
36 });
37 }
38}
No código anterior, o controlador updateUser atualiza um usuário.
Em seguida, vamos criar as rotas que utilizarão os drivers.

rotas

No subdiretório routes, crie um arquivo index.tse user.routes.ts .
Em index.ts, insira o seguinte código:
1import { Router } from 'express';
2import userRoute from './user.route';
3
4// Index
5const indexRoute = Router();
6
7indexRoute.get('', async (req, res) => {
8 res.json({ message: 'Welcome User' });
9});
10
11indexRoute.use('/users', userRoute);
12
13export default indexRoute;
14
15Next, in user.routes.ts enter the following code:
16import { Router } from 'express';
17import {
18 createUser,
19 deleteUser,
20 getUser,
21 getUsers,
22 updateUser,
23} from '../controllers/user.controller';
24
25// Users layout Route
26const userRoute = Router();
27
28userRoute.post('', createUser);
29userRoute.get('', getUsers);
30userRoute.get('/:userid', getUser);
31userRoute.delete('/:userid', deleteUser);
32userRoute.patch('/:userid', updateUser);
33
34export default userRoute;

Testando com o Postman

A rota GET pode ser visualizada no navegador, mas para verificar as outras rotas, usaremos a ferramentaPOSTMAN.

POSTAR

Vamos criar um novo usuário por meio do método POST. Na barra de endereço no Postman, insira a URL de solicitação http://localhost:3000/users, insira a carga útil e clique no botão enviar. Receberemos de volta o JSON correto e também o status de 201 — confirmando que um recurso foi criado. insira a descrição da imagem aqui Solicitação POST: criar um usuário

OBTER

O método GET é usado para buscar todos os usuários. Ele não requer carga útil. insira a descrição da imagem aqui GET Request: Get all Users
No entanto, para buscar um único usuário, precisamos fornecer o ID do usuário. O ponto de extremidade será http://localhost:3000/users/id.
insira a descrição da imagem aqui GET Request: Get a single user

EXCLUIR

Para o método DELETE, será fornecido o id do usuário que está sendo excluído. Novamente, estamos usando o endpoint http://localhost:3000/users/id. insira a descrição da imagem aqui DELETE: delete a user

REMENDO

Para o método PATCH também temos que fornecer um ID do usuário que está sendo atualizado. Usaremos o ponto de extremidade http://localhost:3000/users/id. insira a descrição da imagem aqui PATCH: update a user
Observe que passamos um valor inválido james.com no campo de e-mail e ele é considerado válido. Esse não será o caso depois que implementarmos o middleware de validação.

Validação com Zod

Agora, vamos validar a carga útil das solicitações recebidas (POST, PATCH) para garantir que elas atendam ao formato de dados necessário, conforme especificado em nosso modelo — ou seja, um e-maildeve ser um endereçoe-mail válido (não qualquer string).

Esquema de validação

Primeiro, criaremos um esquemaTrophyllum para descrever o formato de dados necessário.
Crie um subdiretório schemas no diretório src e, em seguida, crie um arquivouser.schema.ts.
Digite o seguinte código em user.schema.ts:
1import { z } from 'zod';
2
3export const createUserSchema = z
4 .object({
5 name: z.string().min(1),
6 email: z.string().email(),
7 phoneNumber: z.string().regex(/^\d+$/),
8 gender: z.enum(['male', 'female', 'others']),
9 })
10 .strict(); //strict prevents the schema from validating payloads with properties not in the schema
11
12export const updateUserSchema = createUserSchema.partial(); //creates a partial schema from createUserSchema where all properties are optional
No código anterior, os seguintes esquemas foram criados:
  • createUserSchema: valida a carga útil que chega ao controlador createUser por meio da solicitação POST.
  • updateUserSchema: Valida a carga útil que chega ao controlador updateUser.

Middleware de validação

Agora, vamos criar um middleware de validação que usa o esquema para validar uma carga de entrada.
1import { NextFunction, Request, Response } from 'express';
2import { ZodSchema } from 'zod';
3
4// Validation middleware
5export const validateSchema =
6 (schema: ZodSchema) => (req: Request, res: Response, next: NextFunction) => {
7 // parse request body
8 const { success, error } = schema.safeParse(req.body);
9
10 // handle non-compliant request body
11 if (!success) {
12 return res.status(401).json({
13 status: false,
14 message: error.errors
15 .map((t) => `${t.path[0] ?? ''}: ${t.message}`)
16 .join(', '),
17 });
18 }
19
20 next();
21 };
No código anterior, o esquema Zod é usado para analisar o corpo da solicitação. Se a análise for bem-sucedida, a próxima função será chamada. Caso contrário, uma resposta JSON com um código de status 401 e uma mensagem de erro será retornada.

Usando o middleware de validação

Agora, vamos modificar o arquivouser.routes.ts adicionando o middleware de validação às rotas createUser e updateUser.
1import { Router } from 'express';
2import {
3 createUser,
4 deleteUser,
5 getUser,
6 getUsers,
7 updateUser,
8} from '../controllers/user.controller';
9import { validateSchema } from '../middlewares/validation.middleware';
10import { createUserSchema, updateUserSchema } from '../schemas/user.schema';
11
12// Users layout Route
13const userRoute = Router();
14
15userRoute.post('', validateSchema(createUserSchema), createUser);
16userRoute.get('', getUsers);
17userRoute.get('/:userid', getUser);
18userRoute.delete('/:userid', deleteUser);
19userRoute.patch('/:userid', validateSchema(updateUserSchema), updateUser);
20
21export default userRoute;
Em comparação com nossa implementação anterior (sem validação), o envio de uma carga inválida retornará um erro agora.
Vamos testar o método PATCH novamente: insira a descrição da imagem aqui PATCH: Invalid e-mail field
Desta vez, obtemos um erro indicando que o valor do campo de e-mail é inválido.
Agora, se usarmos um endereço de e-mail válido, os erros desaparecerão: insira a descrição da imagem aqui PATCH: Campo de e-mail válido

Conclusão

Neste tutorial, criamos uma API CRUD simples com Express, MongoDB e Sod. Você aprenderam como criar um servidor com Express, configurar um esquema Prisma, validar cargas úteis com Sod e testar API com Postman. Sinta-se livre para clonar o projeto no GitHub, inscrever-se no MongoDB Atlase construir sobre esta base. Se você quiser continuar a conversa, junta-se a nós na Comunidade de desenvolvedores MongoDB.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Criando gráficos de AI com Rivet e MongoDB Atlas Vector Search para potencializar aplicativos de AI


Sep 18, 2024 | 10 min read
Início rápido

Instâncias sem servidor do MongoDB Atlas: início rápido


Aug 13, 2024 | 4 min read
Tutorial

Parte #3: pesquise seus dados semanticamente com o Atlas Vector Search do MongoDB


Sep 18, 2024 | 6 min read
Tutorial

Usando o Confluent Cloud com o Atlas Stream Processing


Nov 19, 2024 | 5 min read
Sumário