Deploy e Segurança

Área: Backend | Nível recomendado: Iniciante

Esta missão foca em levar sua aplicação para a nuvem, utilizando o Render.com para hospedagem. Aprenderemos também a importância das variáveis de ambiente para a segurança do projeto, utilizando o arquivo .env para armazenar informações sensíveis.

Vídeo

Link direto: https://youtu.be/zeO6BYTfLls

Tópicos

  1. Preparação para o Deploy:

    • Revisão do código para garantir que está pronto para produção.

    • Instalação de pacotes necessários para produção, como o dotenv.

  2. Segurança de Informações Sensíveis:

    • Introdução ao conceito de variáveis de ambiente.

    • Criação e configuração do arquivo .env.

  3. Deploy no Render.com:

    • Criação de uma conta no Render.com.

    • Configuração do projeto no Render.com para deploy.

    • Lançamento da aplicação no ambiente de produção.

Material de Apoio

Repositório no GitHub

PDF para Download

Miro

Exercícios de Fixação

Use esses exercícios para reforçar o que acabou de aprender. Se errar, leia a explicação para entender melhor o conceito.

Qual comando usamos para instalar o pacote dotenv?

A) npm install dotenv

B) npm install env

C) npm install dotenv-cli

D) npm install environment

Resposta correta

Qual comando usamos para instalar o pacote dotenv?

Resposta Correta: A

Feedback: O comando npm install dotenv é usado para instalar o pacote dotenv, que carrega variáveis de ambiente de um arquivo .env para process.env.


Complete o código para carregar as variáveis de ambiente do arquivo `.env`.
________('dotenv').config();
const express = require('express');
const app = express();

const dbUrl = process.env._________;

app.listen(3000, function () {
  console.log("Aplicação rodando em http://localhost:3000");
});
Resposta correta

Complete o código para carregar as variáveis de ambiente do arquivo .env.

Resposta Correta:

require('dotenv').config();
const dbUrl = process.env.DATABASE_URL;

Feedback: A função require('dotenv').config() carrega as variáveis de ambiente do arquivo .env, e process.env.DATABASE_URL acessa a URL do banco de dados.


Verdadeiro ou Falso: As variáveis de ambiente devem ser comitadas no repositório.

A) Verdadeiro

B) Falso

Resposta correta

Verdadeiro ou Falso: As variáveis de ambiente devem ser comitadas no repositório.

Resposta Correta: B

Feedback: Falso. As variáveis de ambiente contêm informações sensíveis e não devem ser comitadas no repositório. Em vez disso, devem ser armazenadas em arquivos .env que são ignorados pelo Git.


Qual serviço usamos para realizar o deploy da aplicação?

A) Heroku

B) Render.com

C) AWS

D) DigitalOcean

Resposta correta

Qual serviço usamos para realizar o deploy da aplicação?

Resposta Correta: B

Feedback: Render.com é o serviço utilizado para realizar o deploy da aplicação nesta missão.


Qual é a importância de usar variáveis de ambiente para armazenar informações sensíveis, como a URL do banco de dados?

A) Para facilitar o compartilhamento de credenciais com devs da equipe.

B) Para garantir que as informações sensíveis não sejam expostas no código-fonte.

C) Para permitir que o código-fonte seja mais compacto.

D) Para evitar a necessidade de autenticação ao acessar o banco de dados.

Resposta correta

Qual é a importância de usar variáveis de ambiente para armazenar informações sensíveis, como a URL do banco de dados?

Resposta Correta: B

Feedback: Usar variáveis de ambiente para armazenar informações sensíveis garante que essas informações não sejam expostas no código-fonte, aumentando a segurança do projeto.

Exercícios de Validação

Esses exercícios testarão sua compreensão prática. Revise o feedback para melhorar suas habilidades.

Desafio de Código

Crie um script que carregue variáveis de ambiente a partir de um arquivo .env e exiba essas variáveis no console. O script deve também validar se todas as variáveis necessárias estão presentes.

  • Implementar o script no arquivo config.js.

Resposta esperada
config.js
require('dotenv').config();
const requiredEnvVars = ['DATABASE_URL', 'PORT'];

requiredEnvVars.forEach((varName) => {
  if (!process.env[varName]) {
    throw new Error(`Variável de ambiente ${varName} não definida.`);
  }
});

console.log('Variáveis de ambiente carregadas com sucesso:');
requiredEnvVars.forEach((varName) => {
  console.log(`${varName}: ${process.env[varName]}`);
});

Feedback: Certifique-se de que todas as variáveis de ambiente necessárias estão definidas no arquivo .env e que o script está validando corretamente a presença dessas variáveis.

Revisão de Código

const express = require('express');
const app = express();
const dbUrl = 'mongodb+srv://username:password@cluster0.mongodb.net';

app.use(express.json());

app.listen(3000, function () {
  console.log(`Aplicação rodando em http://localhost:${port}`);
});
Resposta Correta

Erros:

  1. Variáveis sensíveis como a URL do banco de dados não devem estar hardcoded no código.

  2. Falta o carregamento das variáveis de ambiente a partir do arquivo .env.

require('dotenv').config();
const express = require('express');
const app = express();
const dbUrl = process.env.DATABASE_URL;

app.use(express.json());

app.listen(3000, function () {
  console.log(`Aplicação rodando em http://localhost:${port}`);
});

Feedback: As variáveis sensíveis devem ser armazenadas em um arquivo .env e carregadas usando o pacote dotenv. Isso aumenta a segurança do projeto ao evitar a exposição de informações sensíveis no código-fonte.

Projeto Prático

Implemente um CRUD completo para gerenciar uma entidade de "Eventos" em uma aplicação usando ExpressJS e MongoDB. Os eventos devem ter as propriedades "nome", "data" e "local". Crie endpoints para adicionar, listar, atualizar e deletar eventos. Se o evento não for encontrado, o endpoint deve responder com "Evento não encontrado". Além disso, implemente o uso de variáveis de ambiente para as informações sensíveis e faça o deploy no Render.com.

Tarefas

  1. Configuração Inicial:

    • Inicialize um novo projeto NodeJS.

    • Instale o ExpressJS, MongoDB Driver e dotenv.

    • Configure o Nodemon para reiniciar o servidor automaticamente.

    • Crie um arquivo .env e adicione as variáveis de ambiente necessárias.

  2. Conexão com o MongoDB:

    • Conecte-se ao MongoDB utilizando o MongoClient e as variáveis de ambiente.

    • Inicialize o banco de dados e a collection "eventos".

  3. Implementação dos Endpoints:

    • Implemente um endpoint para adicionar um novo evento (POST /eventos).

    • Implemente um endpoint para listar todos os eventos (GET /eventos).

    • Implemente um endpoint para obter um evento específico por ID (GET /eventos/:id).

    • Implemente um endpoint para atualizar um evento por ID (PUT /eventos/:id).

    • Implemente um endpoint para deletar um evento por ID (DELETE /eventos/:id).

  4. Deploy da Aplicação:

    • Realize o deploy da aplicação no Render.com e garanta seu funcionamento correto.

Código Esperado
index.js
require('dotenv').config();
const express = require("express");
const { MongoClient, ObjectId } = require("mongodb");
const app = express();
app.use(express.json());

const dbUrl = process.env.DATABASE_URL;
const client = new MongoClient(dbUrl);

async function main() {
  await client.connect();
  const db = client.db('app');
  const collection = db.collection('eventos');

  // Endpoint para adicionar um novo evento
  app.post("/eventos", async function (req, res) {
    const novoEvento = req.body;

    if (!novoEvento.nome || !novoEvento.data || !novoEvento.local) {
      return res.status(400).send('Corpo da requisição deve conter as propriedades nome, data e local.');
    }

    await collection.insertOne(novoEvento);
    res.status(201).send(novoEvento);
  });

  // Endpoint para listar todos os eventos
  app.get("/eventos", async function (req, res) {
    const eventos = await collection.find().toArray();
    res.send(eventos);
  });

  // Endpoint para obter um evento específico por ID
  app.get("/eventos/:id", async function (req, res) {
    const id = req.params.id;
    const evento = await collection.findOne({ _id: new ObjectId(id) });

    if (!evento) {
      return res.status(404).send('Evento não encontrado.');
    }

    res.send(evento);
  });

  // Endpoint para atualizar um evento por ID
  app.put("/eventos/:id", async function (req, res) {
    const id = req.params.id;
    const novoEvento = req.body;

    if (!novoEvento.nome || !novoEvento.data || !novoEvento.local) {
      return res.status(400).send('Corpo da requisição deve conter as propriedades nome, data e local.');
    }

    const resultado = await collection.updateOne({ _id: new ObjectId(id) }, { $set: novoEvento });

    if (resultado.matchedCount === 0) {
      return res.status(404).send('Evento não encontrado.');
    }

    res.send('Evento atualizado com sucesso.');
  });

  // Endpoint para deletar um evento por ID
  app.delete("/eventos/:id", async function (req, res) {
    const id = req.params.id;
    const resultado = await collection.deleteOne({ _id: new ObjectId(id) });

    if (resultado.deletedCount === 0) {
      return res.status(404).send('Evento não encontrado.');
    }

    res.send('Evento deletado com sucesso.');
  });

  app.listen(3000, function () {
    console.log(`Aplicação rodando em http://localhost:3000`);
  });
}

main();

Feedback Detalhado

  • Verificação dos Endpoints: Certifique-se de testar cada rota (/eventos, /eventos/:id, /eventos com POST, PUT e DELETE) acessando http://localhost:3000 e verificando as respostas.

  • Uso de Variáveis de Ambiente: Certifique-se de que as informações sensíveis, como a URL do banco de dados, estão sendo carregadas do arquivo .env.

  • Deploy: Realize o deploy da aplicação no Render.com e garanta que todas as funcionalidades estejam funcionando corretamente no ambiente de produção.

Last updated