Introdução a ORM no Node.js com sequelize

Negócios Tecnologia

Introdução

Elaborar um banco de dados em muitos casos pode ser uma das tarefas mais complexas de todo o projeto. Decidir qual banco de dados utilizar em meio a tantos como: mysql, sqlserver, oracle, sqlite , postgre, mongodb e etc. Decidir se usaremos um banco relacional ou não, imaginar como serão os fluxos da nossa aplicação para através disso desenhar todo o escopo. Complexo, não é?

Afinal cada caso é um caso, e pensando nisso foram desenvolvidas algumas técnicas! Entre elas a que iremos comentar hoje, o famoso ORM ou Mapeamento Objeto Relacional para os mais chegados. Para diminuir a complexidade, já que o ORM torna o banco de dados mais próximo da arquitetura de classe, removendo os comando SQL de vista, para que possamos focar em “Qual é o fluxo que minha aplicação deve seguir” e deixando de lado “Qual é a query que eu deveria usar aqui? “.

Então nesse aspecto iremos abordar um pouco sobre o que são ORM, suas práticas e um exemplo em um projeto node js bem simples. Além disso, darei algumas dicas sobre organização de projeto.

ORM o que é e como funciona? 

Como já citei anteriormente um ORM é um Mapeamento Objeto Relacional, sua base consiste em manter o uso de orientação a objetos  e um pouco do conceito de  non-query. Pois serão raros os momentos onde teremos que escrever uma linha de código SQL para esse tipo de ferramenta.

Outro fato muito importante e curioso sobre os ORM é que eles operam como um agente de banco de dados, sendo possível através de pouquíssimas mudanças, utilizar o mesmo código para mais de um banco de dados. Não importa se ele está em Mysql, SqlServer ou até mesmo Oracle! Ele consegue agir da mesma forma em alguns bancos de dados, você só precisa mudar o driver de conexão e está pronto para uso.

Neste conceito é importante lembrar que cada uma de nossas tabelas são vistas como uma instância de uma classe, tendo suas características declaradas diretamente na sua classe “esquema”.

Quando trabalhamos com esse tipo de esquema sempre teremos um arquivo de configuração, responsável por fornecer os dados para que o componente de ORM possa se comunicar com o banco e aplicação.

Uma outra questão que pode causar dúvidas é como gerar o banco de dados através dessas classes que comentamos anteriormente. Bom veremos isso na prática mais a abaixo.

Vamos exemplificar o ORM através do node js, por ser uma linguagem de fácil implementação e ótima para entender alguns conceitos, já que não necessita muitos requisitos para funcionar. Basta ter apenas o node instalado! 

O package que escolhi para exemplificar e demonstrar o ORM foi o sequelize, pois ele é baseado no conceito de promise e aceita os seguintes bancos de dados:  Postgres, MySQL, MariaDB, SQLite and Microsoft SQL Server.  Caso tenham interesse em conhecer mais sobre a ferramenta, aqui está o link do sequelize: https://sequelize.org/v5/

Iniciando o Projeto

Usaremos neste projeto: 

  • Mysql
  • NodeJS
  • Sequelize -> yarn add sequelize -D
  • Sucrase -> yarn add sucrase -D
  • Yarn -> npm i -g yarn

Usaremos o seguinte MER (Modelo de Entidade Relacional)

Agora que já temos a estrutura básica que iremos trabalhar, precisamos criar o banco de dados na nossa instância do mysql. No meu caso estou utilizando o Workbench e criando a base com as seguintes configurações:

Agora que criamos a base de dados, vamos iniciar nosso projeto nodejs e ver o sequelize em prática!

Para iniciar vamos criar um diretório para nosso projeto:

E então receberemos a seguinte tela:

A partir deste momento teremos o arquivo package.json o que tornará nosso projeto uma aplicação node js, agora vamos abrir nosso projeto no VsCode ou qualquer outro editor de sua preferência, aqui seguirei com VsCode!

Powered by Rock Convert
Powered by Rock Convert

Abaixo teremos a estrutura base que trabalharemos:

Mas o que deve conter em cada pasta? Quais são as responsabilidades de cada uma?

  • app: Esta pasta contém toda a parte lógica e estrutural de nossa aplicação, é nela que definimos nossos controllers, models, enums, util, helpers, convertors, validations, exceptions e services.
  • app/controllers: Responsável por armazenar todos os controllers de nossa aplicação, centralizados em um único lugar. Geralmente é onde encontramos algumas das regras de negócio.
  • app/models: Responsável por armazenar todos as models da nossa aplicação, que neste projeto serão as classes de instâncias do ORM .
  • config: Responsável por armazenar todos os nossos arquivos de configuração e starter’s de alguns processos ou serviços da aplicação.
  • database: Nesta pasta teremos a estrutura responsável por organizar as migrations e seeds que falaremos mais para frente.
  • database/migrations: Responsável por organizar nossas migrations.
  • database/seeds: Responsável por armazenar os arquivos de seed.

Vamos começar instalando algumas dependências e criando alguns arquivos para testar o funcionamento de nossa nova aplicação.

Você pode executar os comandos acima ou apenas adicionar/substituir estas linhas no package.json e executar:

 "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "sequelize": "^5.21.7"
  },
  "devDependencies": {
    "nodemon": "^2.0.3",
    "sequelize-cli": "^5.5.1",
    "sucrase": "^3.13.0"
  }
yarn

O primeiro passo é conseguir  fazer uma API bem simples que já possa retornar algo para que possamos começar o desenvolvimento do projeto. Para testar as rotas que vamos criar na API recomendo o uso do Insomnia.

Bora coda?

Para continuar com nosso projeto organizado, iremos criar três novos arquivos em “src/”

const express = require('express');
const routes = require('./routes');
const cors = require('cors')
//Criamos uma classe para trabalhar com apenas uma instancia do server
class App {
    constructor(){
        this.server = express();
        this.middlewares()
        this.routes()
    }
 
    //Onde será configurado nossas rotas
    routes(){
        this.server.use(routes)
    }
 
    //Se ocorrerá algum tipo de middleware na aplicação
    middlewares(){
        this.server.use(cors())
        this.server.use(express.json())
    }
}
 
module.exports = new App().server;
const {Router} = require('express');
const routes = Router();
 
routes.get('/',function(req,res){
    return res.json({
        ok:true
    })
})
module.exports = routes;
const app = require('./app')
 
app.listen(3333, function(){
    console.log("running on port 3333")
})

Após criarmos esses arquivos, vamos rodar no terminal o seguinte comando :

node src/server.js

E ao testarmos a rota “/” no insomnia, temos que ter o  seguinte resultado:

Se o seu  retorno for igual ao de cima significa que tudo ocorreu bem, agora vamos configurar o sucrase & nodemon. O nodemon será usado para que a cada alteração salva no nosso projeto ele seja recompilado  automaticamente, assim não precisamos ficar parando a aplicação e rodando  “node src/server.js” a cada modificação. E o sucrase será utilizado no lugar do commonJS, para que possamos usar o import & exports.

Para configurar o nodemon precisamos ir até: 

./package.json

E adicionar a propriedade “scripts”

"scripts": {
  "dev": "nodemon src/server.js"
},

Desta forma a próxima vez que precisar rodar o projeto,  basta executar o seguinte comando 

yarn dev

Já para configurar o sucrase precisamos criar um novo arquivo onde o nodemon irá interpretar.

  • ./nodemon.json
{
    "execMap": {
        "js": "sucrase-node"
    }
}

Assim que  tiver incluído essas linhas, poderemos começar a trabalhar com imports/exports. Hora de refatorar tudo!

  • src/app.js
import express from 'express';
import routes from './routes';
import cors from 'cors';
 
//Criamos uma classe para trabalhar com apenas uma instancia do server
class App {
    constructor(){
        this.server = express();
        this.middlewares()
        this.routes()
    }
 
    //Onde será configurado nossas rotas
    routes(){
        this.server.use(routes)
    }
 
    //Se ocorrerá algum tipo de middleware na aplicação
    middlewares(){
        this.server.use(cors())
        this.server.use(express.json())
    }
}
 
export default new App().server;
  • src/routes.js
import { Router } from 'express';
const routes = Router();
 
routes.get('/',function(req,res){
    return res.json({
        ok:true
    })
})

export default routes;

export default routes;

  • src/server.js
import app from './app'
 
app.listen(3333, function(){
    console.log("running on port 3333")
})

Neste momento do projeto finalizamos as configurações do sucrase & nodemon e o projeto está pronto para iniciar a parte do sequelize, mas isso ficará para uma segunda parte deste artigo! 

Acompanhe nosso blog para não perder a segunda parte desse projeto!