Introdução
Dando continuidade ao meu artigo anterior sobre Redis, hoje irei demonstrar como criar uma API utilizando Node.js, MongoDB e o Redis como cache. Caso tenha interesse em ler o artigo anterior, segue o link:
Para pular a etapa de criação de um novo projeto, eu irei utilizar um que eu desenvolvi em um artigo anterior. Caso tenha interesse em clonar esse projeto, segue o link no GitHub: node-express.
Estrutura do projeto
O projeto está bem simples, eu criei um controller contendo os 5 verbos para um CRUD e um diretório para criação das rotas. Abaixo, você tem uma imagem demonstrando a estrutura desse projeto:

Para os próximos passos, será necessário um editor de textos. Eu irei utilizar o VS Code, mas você pode escolher um de sua preferência.
O primeiro passo será baixar as bibliotecas necessárias para o utilizar o Redis e o Mongoose. Para isso, abra um terminal e navegue até o seu projeto. Em seguida, execute o comando abaixo:
npm i body-parser mongoose redis --save
O próximo passo será a criação de um Schema. Para isso, crie um arquivo chamado db.js no seguinte caminho ./src/config/db.js. Agora abra esse arquivo no seu editor de textos e atualize ele com o trecho de código abaixo:
var mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1/db_employees');
var Schema = mongoose.Schema;
var personSchema = new Schema({
name: String,
mail: String,
role: String
});
var Person = mongoose.model('Person', personSchema);
module.exports = Person;
O arquivo acima irá criar uma collection. Nós iremos utilizar ela nos próximos passos desse artigo.
Agora, para deixar o código mais organizado, vamos criar um diretório no nosso projeto para os nossos repositórios. Para isso, crie um novo diretório no seguinte path: ./src/repositories/, e dentro dele um arquivo chamado personRepository.js.

Esse repositório será responsável pela conexão com o Schema. Atualize o arquivo personRepository.js com o código abaixo:
'use strict';
var mongoose = require('mongoose')
var Person = require('../config/db');
module.exports = new class PersonRepository {
getAll() {
return Person.find();
}
getById(id) {
return Person.findById(id);
}
create(person) {
return Person.create(person);
}
update(id, person) {
const updatedperson = {
name: person.name,
mail: person.mail,
role: person.role,
}
return Person.findByIdAndUpdate(id, updatedperson, { new: true });
}
delete(id) {
return Person.findByIdAndRemove(id);
}
}
Antes de atualizar o controller, vamos adicionar o bodyParser no projeto. Abra o seu arquivo app.js e atualize ele com o código abaixo.
const express = require('express');
const app = express();
const router = express.Router();
const bodyParser = require("body-parser");
//Rotas
const index = require('./routes/index');
const personRoute = require('./routes/personRoute');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use('/', index);
app.use('/person', personRoute);
module.exports = app;
Agora atualize o seu arquivo ./src/controllers/personController.js com o código a seguir:
'use strict';
const PersonRepository = require('../repositories/personRepository');
exports.get = (req, res, next) => {
PersonRepository.getAll()
.then((person) => {
res.status(200).send(person);
}).catch(err => res.status(500).send(err))
};
exports.getById = (req, res, next) => {
PersonRepository.getById(req.params.id)
.then((person) => {
res.status(200).send(person);
}).catch(err => res.status(500).send(err))
};
exports.post = (req, res, next) => {
const p = req.body;
PersonRepository.create(p)
.then((person) => {
res.status(200).send(person);
}).catch(err => res.status(500).send(err))
};
exports.put = (req, res, next) => {
const p = req.body;
PersonRepository.update(req.params.id, p)
.then((person) => {
res.status(201).send(person);
}).catch(err => res.status(500).send(err))
};
exports.delete = (req, res, next) => {
PersonRepository.delete(req.params.id)
.then((person) => {
res.status(200).send('delete succeeded!');
}).catch(err => console.error.bind(console, `Error ${err}`))
};
Navegando rapidamente pelo código acima você tem:
- 03: chamada para o repositório PersonRepository
- 05 a 43: implementação dos verbos com a chamada ao nosso PersonRepository
Testando as rotas
Para não precisar instalar o MongoDB no meu computador, eu irei utilizar ele dentro de um contêiner Docker. Caso tenha interesse em utilizar o Mongo com Docker, segue link de um artigo onde eu demonstro esse passo a passo:
Agora, para testar as nossas rotas eu irei utilizar o postman. Caso não conheça ele ainda, o postman nos permite enviar requisições HTTP e obter suas respostas.
POST
A primeira rota que nós precisamos testar é o post, ela que irá cadastrar os nossos registros. Com o postman aberto, preencha ele conforme a imagem abaixo:

GET
Agora altere o verbo para GET e veja o resultado abaixo:

GETById
Buscando uma pessoa pelo seu Id:

PUT
Para validar o PUT, eu irei atualizar o campo role para System Architect.

DELETE
Agora vamos deletar o nosso registo:

Bom, com isso nós conseguimos verificar que todos os nossos verbos estão funcionando corretamente. Para que possamos testar o Redis, será necessário ter alguns registros cadastrados. Para isso, eu irei cadastrar o Zé Maria 10x.
Configurando o Redis
Para não precisar instalar o Redis no meu computador, eu irei utilizar ele da mesma forma que estou utilizando o Mongo, dentro de um contêiner Docker. Caso tenha interesse em saber como criar um contêiner com Redis, segue link de um artigo onde eu demonstro esse passo:
O próximo passo será adicionar o Redis no nosso controller. Para isso, atualize o arquivo personController.js com o trecho de código abaixo:
'use strict';
const PersonRepository = require('../repositories/personRepository');
var redis = require('redis');
var client = redis.createClient();
exports.get = (req, res, next) => {
client.get('allpersons', function (err, reply) {
if (reply) {
console.log('redis');
res.send(reply)
} else {
console.log('db');
PersonRepository.getAll()
.then((person) => {
client.set('allpersons', JSON.stringify(person));
client.expire('allpersons', 20);
res.status(200).send(person);
}).catch(err => res.status(500).send(err))
}
});
};
exports.getById = (req, res, next) => {
PersonRepository.getById(req.params.id)
.then((person) => {
res.status(200).send(person);
}).catch(err => res.status(500).send(err))
};
exports.post = (req, res, next) => {
const p = req.body;
PersonRepository.create(p)
.then((person) => {
res.status(200).send(person);
}).catch(err => res.status(500).send(err))
};
exports.put = (req, res, next) => {
const p = req.body;
PersonRepository.update(req.params.id, p)
.then((person) => {
res.status(201).send(person);
}).catch(err => res.status(500).send(err))
};
exports.delete = (req, res, next) => {
PersonRepository.delete(req.params.id)
.then((person) => {
res.status(200).send('delete succeeded!');
}).catch(err => console.error.bind(console, `Error ${err}`))
};
O passo anterior foi bem simples, eu adicionei o Redis na linha 05, e em seguida eu criei um cliente na linha 06, depois eu criei um chave chamada allpersons que deve expirar em 20 segundos. Para verificar se a aplicação está batendo no banco ou no Redis, eu criei dois consoles retornando: Redis quando estiver no cache e um outro db para quando a API requisitar os dados do mongo.
Testando o Cache
Agora. para verificar se o Redis está configurado corretamente, execute o código novamente e note no seu terminal que ele bate uma vez no banco e depois fica no Redis por 20 segundos. Abaixo você tem uma imagem demonstrando esse passo:

Com isso nós finalizamos esse artigo. O meu intuito aqui foi demonstrar uma das formas de melhorar a performance dos nossos sistemas. Caso tenha interesse em baixar o código fonte desenvolvido nesse artigo, segue o link no GitHub:
Espero ter ajudado e até um próximo artigo, pessoal!




