> For the complete documentation index, see [llms.txt](https://salvatore-academy.gitbook.io/dev-fullstack-web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://salvatore-academy.gitbook.io/dev-fullstack-web/academia/missoes-de-backend/deploy-e-seguranca.md).

# Deploy e Segurança

{% hint style="info" %}
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.
{% endhint %}

## Vídeo

{% embed url="<https://www.youtube.com/watch?v=zeO6BYTfLls&ab_channel=PauloSalvatore&a=1>" %}

**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

{% embed url="<https://github.com/SalvatoreAcademy/backend-missao-aprendizado-iniciante-deploy-e-seguranca>" %}

### PDF para Download

{% file src="/files/EVfStd6ORmWgJAJBtrwf" %}

### Miro

{% embed url="<https://miro.com/app/board/uXjVNQ6PZjQ=/?moveToWidget=3458764587647670382&cot=14>" %}

## Exercícios de Fixação

{% hint style="info" %}
Use esses exercícios para reforçar o que acabou de aprender. Se errar, leia a explicação para entender melhor o conceito.
{% endhint %}

<details>

<summary>Qual comando usamos para instalar o pacote dotenv?</summary>

A) `npm install dotenv`

B) `npm install env`

C) `npm install dotenv-cli`

D) `npm install environment`

</details>

<details>

<summary>Resposta correta</summary>

**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`.

</details>

***

<details>

<summary>Complete o código para carregar as variáveis de ambiente do arquivo `.env`.</summary>

{% code lineNumbers="true" %}

```javascript
________('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");
});
```

{% endcode %}

</details>

<details>

<summary>Resposta correta</summary>

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

**Resposta Correta**:

```javascript
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.

</details>

***

<details>

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

A) Verdadeiro

B) Falso

</details>

<details>

<summary>Resposta correta</summary>

**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.

</details>

***

<details>

<summary>Qual serviço usamos para realizar o deploy da aplicação?</summary>

A) Heroku

B) Render.com

C) AWS

D) DigitalOcean

</details>

<details>

<summary>Resposta correta</summary>

**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.

</details>

***

<details>

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

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.

</details>

<details>

<summary>Resposta correta</summary>

**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.

</details>

## Exercícios de Validação

{% hint style="info" %}
Esses exercícios testarão sua compreensão prática. Revise o feedback para melhorar suas habilidades.
{% endhint %}

### 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`.

<details>

<summary>Resposta esperada</summary>

{% code title="config.js" lineNumbers="true" %}

```javascript
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]}`);
});
```

{% endcode %}

**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.

</details>

### Revisão de Código

{% hint style="danger" %}
**Analise o código a seguir, encontre e corrija o erro relacionado ao uso de variáveis de ambiente e segurança.**
{% endhint %}

{% code lineNumbers="true" %}

```javascript
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}`);
});
```

{% endcode %}

<details>

<summary>Resposta Correta</summary>

**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`.

{% code lineNumbers="true" %}

```javascript
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}`);
});
```

{% endcode %}

**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.

</details>

### 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.

<details>

<summary>Código Esperado</summary>

{% code title="index.js" lineNumbers="true" %}

```javascript
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();
```

{% endcode %}

**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.

</details>
