Data

8 mai, 2018

CRUD completo com Redis, MongoDB e Node.js

Publicidade

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:

projeto scaffold

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.

estrutura Node Mongo

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:

POST

GET

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

GET

GETById

Buscando uma pessoa pelo seu Id:

Get By 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:

redis com node.js e mongodb

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!