DEV Community

Erandir Junior
Erandir Junior

Posted on

Construindo aplicação do zero com node.js: Parte 4

Depois de desenvolver toda a regra principal da aplicação, vamos começar a implementar de fato as nossas dependências.

Mão na massa

Primeiramente vamos alterar o arquivo .env, que foi criado lá parte 2, deixe o arquivo com as seguintes informações:

APP_PORT=8001

DB_DIALECT=postgres
DB_HOST=db_two_factor
DB_DATABASE=two_factor
DB_USER=root
DB_PASSWORD=root

JWT_SECRET=My@jwt#Secret%

EMAIL_HOST=smtp.gmail.com
EMAIL_USER=email_de_exemplo@gmail.com
EMAIL_PASS=sua_senha
EMAIL_PORT=465
Enter fullscreen mode Exit fullscreen mode

Essas são todas as credenciais necessárias nesse projeto. Recomendo parar e subir os containers novamente, depois, acesse o terminal do serviço node para que possamos instalar nossas bibliotecas.

Outro detalhe é que os dados acima são somente de exemplo, se você tem uma conta do google, assim como eu, altere somente os campos EMAIL_USER e EMAIL_PASS, agora caso queiram utilizar algo diferente, é necessário alterar o EMAIL_HOST e talvez o EMAIL_POST.

Dependências

A primeira dependência que vamos instalar, é uma biblioteca que fará o carregamento das informações contidas no arquivo .env, no terminal, execute o comando abaixo para fazer a instalação:

npm i dotenv
Enter fullscreen mode Exit fullscreen mode

Após isso, crie um arquivo chamado load-env.js dentro de src/infra/env. Nesse arquivo vamos implementar a lógica para que ele consiga ler as informações do nosso arquivo .env. Adicione o código abaixo no arquivo:

import { config } from 'dotenv';

const loadEnv = async () => {
    let env = '';

    if (process.env.NODE_ENV) {
        env = `.${process.env.NODE_ENV}`;
    }

    const configPath = `.env${env}`;

    const result = config({
        path: configPath
    });

    if (result.error) {
        throw result.error
    }
}

export default loadEnv;
Enter fullscreen mode Exit fullscreen mode

Agora, na raiz da nossa aplicação, crie um arquivo chamado index.js com o seguinte conteúdo:

import loadEnv from './src/infra/env/load-env.js';

async function run() {
    await loadEnv();
}

run();
Enter fullscreen mode Exit fullscreen mode

Esse arquivo será o ponto de partida da nossa aplicação. Por enquanto deixemos ele assim, voltaremos a modificá-lo no futuro.

Em seguida, vamos instalar uma biblioteca para manipular senhas, ela será útil por exemplo para criptografar senhas e fazer comparações de hashs:

npm i bcrypt
Enter fullscreen mode Exit fullscreen mode

Agora crie um arquivo chamado password-hash.js, dentro de src/infra/hash, com o conteúdo abaixo:

import IPasswordHash from './../../domain/ipassword-hash.js';
import Bcrypt from 'bcrypt';
import { promisify } from 'util';
const compareAsync = promisify(Bcrypt.compare);

export default class PasswordHash extends IPasswordHash {
    constructor() {
        super();
    }

    compare(password, hash) {
        return compareAsync(password, hash);
    }
}
Enter fullscreen mode Exit fullscreen mode

Basicamente implementamos nosso comparativo de senha, detalhe para o uso da função interna do node chamada promisify, que converte funções callback para promise, facilitando o use de qualquer recurso.

Agora vamos instalar duas bibliotecas muito úteis, a primeira vai servir para gerar um token jwt, e o segundo nos servirá para gerar uuids:

npm i jsonwebtoken short-uuid
Enter fullscreen mode Exit fullscreen mode

Após a instalação, vamos começar por configurar a nossa geração de token jwt. Dentro de src/infra/jwt, crie o arquivo jwt.js, com o seguinte conteúdo:

import IToken from './../../domain/itoken.js';
import JWT from 'jsonwebtoken';

export default class Jwt extends IToken {
    constructor() {
        super();
    }

    generateWebToken(user) {
        const token = JWT.sign({
            id: user.id,
            email: user.email,
        }, process.env.JWT_SECRET);

        return token;
    }
}
Enter fullscreen mode Exit fullscreen mode

Aqui não tenho muito o que falar a não ser recomendar pesquisarem um pouco sobre essa biblioteca para terem noção do quão poderosa ela é.

Agora vamos configurar nosso gerador de uuids, dentro de src/infra/token, crie o arquivo token-service.js, e insira o conteúdo abaixo:

import Short from 'short-uuid';
import IGenerateToken from '../../domain/igenerate-token.js';

export default class TokenService extends IGenerateToken {
    constructor() {
        super();
    }

    getToken() {
        return Short.uuid();
    }

    getEmailToken() {
        return Short.generate();
    }
}
Enter fullscreen mode Exit fullscreen mode

Essa biblioteca vai nos fornecer dois recursos: o primeiro é a geração de um uuid completo, algo como fd5c084c-ff7c-4651-9a52-37096242d81c, além disso, ela também permite a geração de identificadores menores, então o método generate() retornaria algo parecido com isso mhvXdrZT4jP5T8vBxuvm75.

Agora vamos instalar a biblioteca que vai fazer o envio de e-mail:

npm i nodemailer
Enter fullscreen mode Exit fullscreen mode

Após a instalação, vamos configurar nosso serviço de e-mail, dentro do diretório src/infra/email, crie um arquivo chamado body-email-html.js, ele vai conter o conteúdo html que será enviado para o cliente:

const bodyEmailHtml = (token) => {
    return `<!DOCTYPE html>
        <html>
        <head>
        <style>
            .container {
                margin: 10% 20%;
                border-radius: 10px;
                background-color: white;
            }

            .title {
                padding: 1% 0% 0%;
                text-align: center
            }

            p {
                color:blue;
                text-align: center;
                font-family: Arial, sans-serif;
                font-size: 30px;
                padding-bottom: 5%;
            }
        </style>
        </head>
        <body>
            <div class="container">
                <div class="title">
                    <h3>Use the token below to finish login.</h3>
                </div>
                <hr/>
                <p>${token}</p>
            </div>
        </body>
        </html>`;
};

export default bodyEmailHtml;
Enter fullscreen mode Exit fullscreen mode

Ainda dentro do mesmo diretório, crie um arquivo chamado email.js, nele vamos realmente implementar a funcionalidade de envio:

import IEmail from './../../domain/iemail.js';
import nodemailer from "nodemailer";
import bodyEmailHtml from './body-email-html.js';

export default class Email extends IEmail {
    constructor() {
        super();
    }

    async send(user) {
        const transporter = nodemailer.createTransport({
            host: process.env.EMAIL_HOST,
            port: process.env.EMAIL_PORT,
            auth: {
                user: process.env.EMAIL_USER,
                pass: process.env.EMAIL_PASS,
            },
        });

        await transporter.sendMail({
            from: process.env.EMAIL_USER,
            to: user.email,
            subject: "Hello, see you token",
            html: bodyEmailHtml(user.emailToken)
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Como podem ver, não tem nada de complexo, basicamente informamos a configuração de conexão, e após isso enviamos o e-mail para o remetente correto. Outra recomendação é olhar mais detalhadamente essa biblioteca para ter uma noção dos inúmeros outros recursos que ela oferece.

Bem pessoal, a partir de agora faremos algumas instalações bem úteis, porém só vamos configurá-las no próximo artigo. Vamos começar pelo hapi, que fará todo o intermédio entre as requisições web e a nossa aplicação:

npm i @hapi/boom @hapi/hapi @hapi/inert @hapi/vision hapi-swagger joi
Enter fullscreen mode Exit fullscreen mode

Muitos devem conhecer o express ou outra lib que faça a mesma coisa, caso queira utilizar algo diferente do hapi, fiquem a vontade.

Em seguida, vamos instalar um orm, que vai servir para intermediar nossa comunicação e manipulação do banco, eu optei pelo sequelize, mas fique a vontade se quiser utilizar outro:

npm i pg pg-hstore sequelize
Enter fullscreen mode Exit fullscreen mode

E por último, mas não menos importante, vamos instalar uma lib, que é bem útil enquanto você desenvolve.

npm i --save-dev nodemon
Enter fullscreen mode Exit fullscreen mode

O nodemon é bem útil enquanto desenvolvemos, pois não precisaremos reiniciar o servidor a cada alteração. Para vocês que estão seguindo esses artigos, não será tão útil, devido eu ter feito de uma forma mais organizada, mas para mim que fazia o projeto e não segui exatamente a ordem dos artigos, ajudou bastante.

Outro ponto é que essa biblioteca, assim como a de teste, vai ser instalada somente para ambiente de desenvolvimento.

Resumo

Neste artigo, vimos a instalação e uso de algumas dependências, recomendo novamente que pesquisem um pouco mais sobre cada biblioteca instalada, seus recursos, etc.

Se você for um dev mais experiente, e conheça ou queira utilizar outras bibliotecas, deixei claro que você pode fazer isso tranquilamente. Repare que essas mudanças não afetam a nossa lógica principal, esse é um benefício de adotar uma arquitetura que tenha como foco a camada de regras de negócio. Até o próximo artigo.

Top comments (2)

Collapse
 
mentorduncan profile image
mentorduncan

Muito bom material.
Agreço muito por compartilhar!
Irei segui-lo desde o início.

Só não entendi pq a função loadEnv é async
...const loadEnv = async () => {...
?

Collapse
 
erandirjunior profile image
Erandir Junior

@mentorduncan nesse caso aqui realmente não precisaria ser async, acredito que eu tenha feito pensando em algo e no fim esqueci de remover.