Deploy, Node.js e banco de dados com Sequelize

Deploy, Node.js e banco de dados com Sequelize

Ao iniciar na programação, muitas vezes criamos programas ótimos para conseguir uma primeira vaga de emprego, porém, manter o seu software rodando somente de maneira local dificulta muito a apresentação. É muito importante ter seus projetos de fácil acesso a qualquer recrutador. Além disso, no meio profissional, quase todas as aplicações concluídas devem ir para um ambiente online. Sendo assim, partiremos para os conceitos iniciais de Deploy.

Neste artigo veremos como criar um ambiente backend em Node.Js, como integrar um banco de dados a aplicação usando o Sequelize e, por fim, como colocar a aplicação em um Serviço de Nuvem.

O que é Deploy?

Deploy é o ato de colocar uma aplicação “no ar”, é basicamente dar uma URL online para o programa desenvolvido. Normalmente, o build e o deploy da aplicação são responsabilidades dos programadores DevOps, porém, é algo rotineiro dentro do trabalho e é uma ferramenta muito útil para qualquer programador.

O mais comum é ter dois ambientes em deploy:  um para testes e um para quando o site estiver completo. Dessa maneira, antes de entrar nos detalhes do ambiente e do próprio deploy, será necessário entender o conceito de domínio.

O que é Domínio?

O Domínio é o endereço que usamos para acessar o site, é uma parte da URL. As URLS possuem uma infraestrutura facilmente observável em qualquer site da internet e servem para possibilitar o acesso ao seu site sem a necessidade de saber o IP exato.


Por meio das URLS, podemos consumir dados e acessar sites. Sabendo disso, colocaremos um banco de dados no ar e, em seguida, poderemos consumir esse banco de dados em nossa aplicação.

Serviços de Nuvem

Para hospedar nosso site precisamos de um servidor e criar essa infraestrutura é algo que daria muito trabalho. Diversos serviços de hospedagem como Amazon Web Services (AWS), Railway, Heroku, entre outros, surgiram com o objetivo de terceirizar esse trabalho, possibilitando focar  somente em fazer o nosso programa funcionar.

No exemplo a seguir usaremos o Railway para o deploy do banco de dados, do backend e do frontend.

Deploy do banco de dados usando Railway

  • Inicialmente crie uma conta no Railway e clique em New Project.
  • Em seguida, clique em Empty Project e deverá aparecer algo semelhante a isso:


Agora podemos clicar no retângulo no meio da tela e escolher a opção do banco de dados MYSQL. Ao clicar no banco de dados adicionado podemos ver em variables as variáveis de ambiente que serão usadas no arquivo .env futuramente.

  • Em seguida adicionaremos o frontend e o backend. Para isso clique em New e adicione um novo Empty Project, clique nele e vá em Settings.

Na parte de Settings do novo projeto podemos adicionar um domínio aleatório ou um customizado. No nosso caso usaremos esse: backend-tutorial.up.railway.app e front-end.up.railway.app.


Agora que temos os serviços configurados no site iremos associar um código a cada um deles.

Adicionando código ao meu serviço Railway

Para começar, criaremos duas pastas: uma para o frontend e outra para o backend.

mkdir backend

mkdir frontend

Agora entre na pasta backend:

cd backend

npm init -y

Dentro do package.json coloque as seguintes dependências:

Rode o comando a seguir para instalar as dependências:

npm install

Crie o arquivo .gitignore para evitar enviar arquivos desnecessários para o repositório.

touch .gitignore


Crie o arquivo de configurações do Sequelize:

touch .sequelizerc

Crie o arquivo .env local onde armazenaremos as variáveis de ambiente:


Agora criaremos a pasta api e os arquivos routes.js e o server.js:

mkdir api

cd api

touch routes.js

touch server.js

Então saia do /api e criaremos o arquivo de config responsável trazer a configuração de conexão da nossa aplicação com o banco de dados local ou o banco de dados do servidor.

cd ..

mkdir config

cd config

touch config.js

Com isso feito, criaremos os models do nosso banco de dados

cd ..

mkdir models

cd models

touch index.js

touch cards.model.js

 const model = (sequelize, DataTypes) => {
   const CardsModel = sequelize.define('cards', {
     id: {
       type: DataTypes.INTEGER,
       primaryKey: true,
       autoIncrement: true,
       allowNull: false,
     },
     card_brand: DataTypes.STRING
   }, { timestamps: false, tableName: 'cards',  underscored: true});
 
   return CardsModel;
 }
  module.exports = model;

Agora  faremos o migration, ferramenta responsável por controlar o versionamento do banco de dados:

npx sequelize migration:create --name=create-card-model

/migrations/XXXXX-create-card-model.js

Vamos criar o arquivo responsável por popular o banco de dados. No nosso exemplo, estamos criando um banco de dados para cartões de crédito de débito.

npx sequelize seed:generate --name users

/seeders/XXXXX.cards.js

module.exports = {
 up: async (queryInterface, _Sequelize) => {
   await queryInterface.bulkInsert('tasks',
     [{
       card_brand: 'Blastercard'
     },
     {
       card_brand: 'Blisa'
     },
     ], { timestamps: false });
 },


 down: async (queryInterface, _Sequelize) => {
   await queryInterface.bulkDelete('tasks', null, {});
 },
};



Por último, criaremos o controller, o controller será responsável por trazer os dados com o status da requisição.

cd ..

mkdir controllers

touch Cards.js

const { Card } = require('../models');


const getAllCards = async (_req, res) => Card
 .findAll()
   .then((cards)=> res.status(200).json(cards))
   .catch((error)=> {
     console.error(error);
     res.status(500).end()
   });


const getCard = (req, res) => Card
 .findOne({ where: { id: req.params.id } })
   .then((card)=> res.status(200).json(card))
   .catch((error)=> {
     console.error(error);
     res.status(500).end()
   });


module.exports = {
 getAllCards,
 getCard,
}


Finalmente temos nosso banco de dados e backend configurados. Para “sincronizar” o código com o Railway faremos o seguinte:

  • Mande o código desenvolvido anteriormente para um repositório no GitHub.
  • Com o repositório na sua conta, entre no Railway, clique no retângulo do backend e adicione o repositório criado.


A partir disso, podemos acessar o banco de dados por meio da rota que criamos anteriormente. O banco de dados criado no exemplo é bem simples e possui somente 2 cartões, porém seria possível escalar o banco de dados para qualquer tamanho.

Para acessar os dados que o nosso backend disponibiliza, precisamos fazer um fetch. Partindo para a parte do frontend, seria algo assim:

npx create-react-app front-tutorial

mkdir utils

No package.json altere o campo  dependencies e em seguida instale as dependências.

"dependencies": {
   "@testing-library/jest-dom": "5.14.1",
   "@testing-library/react": "11.2.7",
   "@testing-library/user-event": "12.8.3",
   "axios": "0.21.4",
   "clsx": "1.1.1",
   "react": "17.0.2",
   "react-icons": "4.2.0",
   "react-scripts": "4.0.3",
   "web-vitals": "1.1.2"
 },


touch fetch

/utils/fetch.js

Com o fetch feito, criamos um contexto. Isso é  o que possibilita acessarmos os dados do nosso backend.

mkdir context

touch CardContext.js

/context/CardContext.js

import { createContext, useState } from "react";
import cardsApi from '../utils/fetch';


const CardContext = createContext();


export function CardProvider ({ children }) {
 const [cards, setCards] = useState([]);


 const getCards = async () => cardsApi('GET', 'cards')
   .then(({ data: cards }) => setCards(cards));


 const getTask = async (id) => cardsApi('GET', `cards/${id}`)
   .then(({ data: card }) => card);


 const contextValue = {
   cards,
   getTasks,
   getTask,
 };


 return (
   <CardContext.Provider value={ contextValue }>
     { children }
   </CardContext.Provider>
 );
}


export default CardContext;

E, por fim, no App.js renderizamos os dados que vem do nosso banco de dados. Usaremos o Context criado anteriormente para pegar os cartões do banco de dados e em seguida renderizamos eles em HTML por meio da HOF (High Order Function) .map.

import React, { useContext, useEffect } from 'react';
import CardsContext from '../../context/cardsContext';
import './styles.css';


function App() {
 const { cards, getCards } = useContext(CardsContext);


 useEffect(()=>{
   if(cards.length === 0){
     getTasks();
   }
 }, [cards, getCards]);


 return (
   <div
     data-testid="todo-task-list"
     className="item-list"
   >
     {
       cards.length > 0 && cards
         .map(({card_brand }, index) => (
           <li key={index}>{card_brand}</li>
         ))
     }
   </div>
 );
}


export default App;


Ao terminar a aplicação local, podemos dar um push para o repositório e ir para o Railway novamente para conectar o frontend ao código criado.

No Railway clicarmos no retângulo do frontend vamos em Settings e conectamos ao repositório criado anteriormente, então botamos a rota do frontend e é só esperar o build rodar.

Conclusão

Temos uma aplicação funcionando e rodando toda em um ambiente online. Apesar do exemplo ser bem minimalista para focar no deploy, a possibilidade de escalabilidade é incrível e a interface do Railway deixa a visualização dos componentes bem mais clara do que outros serviços que usei.

Praticar o deploy nos nossos projetos é algo crucial já que, praticamente, todos os projetos desenvolvidos profissionalmente irão para um ambiente online e necessitarão de deploy. Sendo assim, recomendo reproduzir o passo a passo anterior com aplicações que já tenha criado anteriormente.

💡
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.Jueves, 5 de enero