Deploy, Node.js y base de datos con Sequelize

Deploy, Node.js y base de datos con Sequelize

Cuando comenzamos a programar, a menudo creamos excelentes programas para obtener un primer trabajo. Sin embargo, mantener tu software ejecutándose solo en modalidad local hace que sea muy difícil de presentar.

Es muy importante que tus proyectos sean fácilmente accesibles para cualquier reclutador. Además, en el entorno profesional, casi todas las solicitudes completadas deben ir a un entorno en línea. Por lo tanto, comenzaremos con los conceptos iniciales de Deploy.

En este artículo veremos cómo crear un entorno backend en Node.Js, cómo integrar una base de datos con la aplicación Sequelize y, finalmente, cómo colocar la aplicación en un Servicio en la Nube.


¿Qué es Deploy?


Deploy es el acto de poner una aplicación “en el aire”, es decir, dar una URL en línea al programa desarrollado. Normalmente, el build y el deploy de la aplicación son responsabilidad de los programadores de DevOps. Sin embargo, es algo rutinario dentro del trabajo y es una herramienta muy útil para cualquier programador.

Lo más común es tener dos entornos de implementación: uno para pruebas y otro para cuando el sitio esté completo. Así, antes de entrar en los detalles del entorno y del propio deploy, será necesario comprender el concepto de dominio.

¿Qué es Dominio?


El Dominio es la dirección que usamos para acceder al sitio web y es parte de la URL. Las URLS tienen una infraestructura fácilmente observable en cualquier sitio web y sirven para permitir el acceso a su sitio web sin necesidad de saber la IP exacta.


A través de URLs, podemos consumir datos y acceder a sitios web. Sabiendo esto, pondremos una base de datos en el aire y luego podremos emplearla en nuestra aplicación.

Servicios en la Nube


Para alojar nuestro sitio web necesitamos un servidor y crear esta infraestructura es algo que llevaría mucho trabajo. Varios servicios de alojamiento como Amazon Web Services (AWS), Railway y Heroku, entre otros, han surgido con el objetivo de externalizar este trabajo, lo que permite centrarse únicamente en hacer que nuestro programa funcione.

En el siguiente ejemplo, usaremos Railway para implementar la base de datos, el backend y el frontend.

Deploy de base de datos con Railway

  • Crea una cuenta en Railway y haz clic en New Project.
  • Luego, haz clic en Empty Project y debería aparecer algo similar a esto:


Ahora podemos hacer clic en el rectángulo en el medio de la pantalla y elegir la opción de base de datos MYSQL. Al hacer clic en la base de datos agregada, podemos ver en variables las variables de entorno que se utilizarán en el archivo .env en el futuro.

  • A continuación agregaremos el frontend y el backend. Para hacer esto, haz clic en New y agrega un nuevo Empty Project, selecciónalo y ve a Settings.

En la parte de Settings del nuevo proyecto, podemos agregar un dominio aleatorio o uno personalizado. En nuestro caso usaremos estos: backend-tutorial.up.railway.app e front-end.up.railway.app.


Ahora que tenemos los servicios configurados en el sitio, asociaremos un código a cada uno de ellos.

Añadir código al servicio Railway


Para comenzar, crearemos dos carpetas: una para el frontend y otra para el backend.

mkdir backend

mkdir frontend

Ahora entra en la carpeta backend:

cd backend

npm init -y

Dentro del package.json coloca las siguientes dependencias:

Ejecuta el comando que viene para instalar las dependencias:

npm install

Crea el archivo .gitignore para evitar enviar archivos innecesarios al repositorio.

touch .gitignore

Crea el archivo de configuración de Sequelize:

touch .sequelizerc

Crea el archivo .env local donde almacenarás las variables de entorno:

Ahora crearemos la carpeta api y los archivos routes.js y server.js:

mkdir api

cd api

touch routes.js

touch server.js

Luego sal de /api y genera el archivo de configuración responsable de nuestra aplicación con la base de datos local o la base de datos del servidor.

cd ..

mkdir config

cd config

touch config.js


Hecho eso, crea los models de nuestra base de datos:

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;

Ahora haremos la migración. La herramienta encargada de controlar el versionado de la base de datos:

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

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

Genera ahora el archivo responsable de llenar la base de datos. En nuestro ejemplo, creamos una base de datos para tarjetas 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, crearemos el controller, responsable por traer los datos con el status da requisición.

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 tenemos nuestra base de datos y backend configurados. Para “sincronizar” el código con Railway haremos lo siguiente:

  • Envía el código desarrollado previamente a un repositorio en GitHub.
  • Con el repositorio en tu cuenta, ingresa a Railway, haz clic en el rectángulo del backend y agrega el repositorio creado.

Desde allí, podemos acceder a la base de datos a través de la ruta que creamos anteriormente. La base de datos creada en el ejemplo es muy simple y tiene solo 2 tarjetas, pero sería posible escalar la base de datos a cualquier tamaño.

Para acceder a los datos que nuestro backend pone a disposición, necesitamos hacer un fetch. Pasando al frontend, sería algo como esto:

npx create-react-app front-tutorial

mkdir utils

En el package.json altera el campo dependencies y luego instala las dependencias.

"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


Hecho el fetch, creamos un contexto, lo que posibilita el acceso a los datos de nuestro 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;

Y finalmente, en App.js renderizamos los datos que provienen de nuestra base de datos. Usaremos el contexto creado anteriormente para obtener las tarjetas de la base de datos y luego las renderizaremos en HTML usando el mapa HOF (High Order Function).

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;

Cuando terminemos con la aplicación local, podemos enviarla al repositorio e ir a Railway nuevamente para conectar la interfaz con el código creado.

En Railway, haz clic en el rectángulo de interfaz, ve a Settings y conéctate al repositorio creado anteriormente, luego coloca la ruta de interfaz y espera a que se ejecute el build.

Conclusión

Tenemos una aplicación funcionando en un entorno en línea. A pesar de que el ejemplo es muy minimalista para centrarse en la implementación, la posibilidad de escalabilidad es increíble y la interfaz de Railway hace que la visualización de los componentes sea mucho más clara que en otros servicios que he usado.

La implementación de nuestros proyectos es crucial, ya que prácticamente todos los proyectos desarrollados profesionalmente irán a un entorno en línea y deberán tener el deploy. Por ello, recomiendo reproducir el paso a paso anterior con aplicaciones que ya hayas creado antes.

💡
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Listopro.

Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.