Criando uma API com Node.js, Express e MongoDB
Esse artigo é baseado no tutorial https://woliveiras.com.br/posts/construindo-uma-api-com-node-js-parte-1-criando-e-listando-dados/
O GitHub deste projeto https://github.com/totemarcal/apiFormik
1- Crie uma pasta chamada apiFormik
2- Acesse a pasta apiFormik e rode:
npm init
3- Vamos instalar o Express e o Nodemon. O Express é nosso framework web e o Nodemon nos ajuda na hora do desenvolvimento para não ser necessário ficar reiniciando o servidor a cada alteração de código fonte.
npm install --save express debug && npm install --save-dev nodemon
4- Abra o Visual Code executando:
code .
5- Edite o arquivo package.json para adicionar o seguinte script:
"scripts": { "dev": "node node_modules/nodemon/bin/nodemon bin/server" }
6- Crie a pasta bin e o arquivo server.js dentro dela (pode ser dentro do Visual Code). Neste arquivo, adicione o seguinte conteúdo:
const app = require('../src/app'); const http = require('http'); const debug = require('debug')('nodestr:server'); // PORT // based on express-generator function normalizePort(val) { const port = parseInt(val, 10); if (isNaN(port)) { return val; } if (port >= 0) { return port; } return false; } const port = normalizePort(process.env.PORT || 3000); app.set('port', port); // error handler function onError(error) { if (error.syscall !== 'listen') { throw error; } const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; switch (error.code) { case 'EACCES': console.error(bind + ' requires elevated privileges'); process.exit(1); case 'EADDRINUSE': console.error(bind + ' is already in use'); process.exit(1); default: throw error; } } // listener handler function onListening() { const addr = server.address(); const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; debug('Listening on ' + bind); } // levanta o server const server = http.createServer(app); server.listen(port); server.on('error', onError); server.on('listening', onListening); console.log(`API is alive on ${port}!`);
7- Crie um pasta chamada src e dentro da pasta crie o arquivo app.js e adicione o seguinte código:
const express = require('express'); // App const app = express(); // Load routes const indexRoutes = require('./routes/index-routes'); // Chama a primeira rota '/' app.use('/', indexRoutes); module.exports = app;
8- Crie a pasta routes dentro de src e dentro da pasta crie o arquivo index-routes.js e adicione o seguinte código:
const express = require('express'); const router = express.Router(); router.get('/', (req, res, next) => { res.status(200).send({ title: 'userFormik', version: '1.0.0' }); }); module.exports = router;
9- Start o servidor com o comando abaixo:
npm run dev

Acesse o endereço localhost:3000

MongoDB
10- Acesse o site mongodb.com/cloud e crie um Cluster

Clique em DataBase Acess e depois em add new user.

Depois volte para a tela de Cluster, clique em Connect e selecione a aba Choose a connection method e copie a Connection String. Configura a liberação de endereços de IP em Network Acess e depois Allow Access from Anywhere.

Configurando o MongoDB
11- Para fazer a conexão com o MongoDB vamos utilizar variáveis de ambiente, que vamos colocar em um arquivo de configuração, e o Mongoose, uma lib que facilita a utilização do MongoDB. Para isso execute o seguinte comando:
npm install --save mongoose dotenv
12- Crie o arquivo .env na raiz do nosso projeto (fora da pasta src) e cole a Connection String copiada anteriormente alterando o usuário e senha.
Salvar e Consultar
13- Crie a pasta models dentro da pasta src e depois crie o arquivo userFormik.js com o seguinte conteúdo:
const mongoose = require('mongoose'); const Schema = mongoose.Schema; const schema = new Schema({ name: { type: String, required: true, trim: true }, username: { type: String, required: true }, password: { type: String, required: true } }); module.exports = mongoose.model('Mentions', schema);
14- Crie uma pasta controllers dentro de src e crie o arquivo apiFormik-controller.js e adicione o seguinte conteúdo:
const repository = require('../repositories/userFormik-repository'); // list exports.listUserFormik= async (req, res) => { try { const data = await repository.listUserFormik(); res.status(200).send(data); } catch (e) { res.status(500).send({message: 'Falha ao carregar userFormik.'}); } }; // create exports.createUserFormik= async (req, res) => { try { await repository.createUserFormik({ name: req.body.name, username: req.body.username, password: req.body.password }); res.status(201).send({message: 'userFormik cadastrada com sucesso!'}); } catch (e) { res.status(500).send({message: 'Falha ao cadastrar userFormik.'}); } };
15- Dentro da pasta src crie uma pasta chamada repositories, dentro dessa pasta crie o arquivo mentions-repository.js e adicione o seguinte código.
// importando o mongoose const mongoose = require('mongoose'); const userFormik = mongoose.model('userFormik'); exports.listUserFormik= async () => { const res = await userFormik.find({}, 'name username -_id'); return res; }; // create exports.createUserFormik= async data => { const user= new userFormik(data); await user.save(); };
15- Navegue até a pasta src e depois routes, crie o arquivo userFomik-routes.js e adicione o seguinte conteúdo:
const express = require('express'); const router = express.Router(); const userFormikController = require('../controllers/apiFormik-controller'); router.get('/', userFormikController.listUserFormik); router.post('/', userFormikController.createUserFormik); module.exports = router;
16- Altere o arquivo app.js com o código seguinte. Com isso temos a nossa aplicação Express conectada com o MongoDB em um cluster na nuvem (cloud).
const express = require('express'); // const mongoose = require('mongoose'); require('dotenv').config(); // App const app = express(); app.use(express.json()); app.use(express.urlencoded({extended: true})); // usamos o mongoose para criar uma conexão com a // connection string do banco de dados que passamos no arqvuio .env mongoose.connect(process.env.DATABASE_CONNECTION_STRING, { useUnifiedTopology: true, useFindAndModify: true, useNewUrlParser: true, useCreateIndex: true }); const db = mongoose.connection; db.on('connected', () => { console.log('Mongoose default connection is open'); }); db.on('error', err => { console.log(`Mongoose default connection has occured \n${err}`); }); db.on('disconnected', () => { console.log('Mongoose default connection is disconnected'); }); // se o usuário matar o processo process.on('SIGINT', () => { db.close(() => { console.log( 'Mongoose default connection is disconnected due to application termination' ); process.exit(0); }); }); // Load models const userFormik = require('./models/userFormik'); // Load routes const indexRoutes = require('./routes/index-routes'); // Chama a primeira rota '/' app.use('/', indexRoutes); const userFomikRoutes = require('./routes/userFomik-routes'); app.use('/userFomik', userFomikRoutes); module.exports = app;
17- Teste no Postman
Validação
18- Para fazer a validação instale a seguinte lib:
npm install --save express-validator
19- Agora vamos importar o check do express-validator, no nosso userFormik-routes.js e adicionar suas validações na hora do POST check(nome do campo do body). O arquivo final ficará assim:
const express = require('express'); const router = express.Router(); const userFormikController = require('../controllers/userFormik-controller'); const { check } = require('express-validator'); router.get('/', userFormikController.listUserFormik); router.post('/', [ check('name').isLength({ min: 7 }).withMessage("O nome precisa ter no mínimo 7 caracteres."), check('username').isLength({ min: 20, max: 280 }).withMessage("A menção precisa ter no mínimo 20 caracteres e no máximo 280.") ],userFormikController.createUserFormik); module.exports = router;
20- No nosso userFormik-controller.js vamos importar o validationResult e no createUserFormik no arquivo userFormik-controller vamos utilizar essa função para retornar um erro, caso o usuário tenha cometido um engano. O arquivo final ficará assim:
const repository = require('../repositories/userFormik-repository'); const { validationResult } = require('express-validator'); // list exports.listUserFormik= async (req, res) => { try { const data = await repository.listUserFormik(); res.status(200).send(data); } catch (e) { res.status(500).send({message: 'Falha ao carregar userFormik.'}); } }; // create exports.createUserFormik= async (req, res) => { try { const {errors} = validationResult(req); if(errors.length > 0) { return res.status(400).send({message: errors}) } await repository.createUserFormik({ name: req.body.name, username: req.body.username, password: req.body.password }); res.status(201).send({message: 'userFormik cadastrada com sucesso!'}); } catch (e) { res.status(500).send({message: 'Falha ao cadastrar userFormik.'}); } };
Atualizando
21- Na pasta repositories, no arquivo userFormik-repository.js adicione a seguinte função:
// update exports.updateMention = async (id, data) => { await Mentions.findByIdAndUpdate(id, { $set: data }); };
22- Agora vamos adicionar a rota para atualização. Para isso na pasta routes edite o arquivo userFormik-routes.js. Perceba que já implementamos as validações.
router.put('/:id', [ check('name').isLength({ min: 7 }).withMessage("O nome precisa ter no mínimo 7 caracteres."), check('username').isLength({ min: 20, max: 280 }).withMessage("A menção precisa ter no mínimo 20 caracteres e no máximo 280.") ], userFormikController.updateUserFormik);
23- Na pasta controller edite o arquivo userFormik-controller.js e adicione o seguinte código:
//update exports.updateUserFormik = async (req, res) => { try { const {errors} = validationResult(req); if(errors.length > 0) { return res.status(400).send({message: errors}) } await repository.updateUserFormik(req.params.id, req.body); res.status(200).send({ message: 'Usuário atualizado com sucesso!' }); } catch (e) { res.status(500).send({message: 'Falha ao atualizar a usuário.'}); } };
24- Teste no Postman e altere o verbo para PUT.

Apagando
25- Na pasta repositories, no arquivo userFormik-repository.js adicione a seguinte função:
//delete exports.deleteUserFormik = async id => { await userFormik.findByIdAndDelete(id); };
26- Agora vamos adicionar a rota para atualização. Para isso na pasta routes edite o arquivo userFormik-routes.js.
router.delete('/:id', userFormikController.deleteUserFormik);
27- Na pasta controller edite o arquivo userFormik-controller.js e adicione o seguinte código:
// delete exports.deleteUserFormik = async (req, res) => { try { await repository.deleteUserFormik(req.params.id); res.status(200).send({ message: 'Usuário removido com sucesso!' }); } catch (e) { res.status(500).send({message: 'Falha ao remover o usuário.'}); } };
28- Teste no Postman e altere o verbo para DELETE.