Exercício - Conectar o Express.js ao Banco de Dados do Azure para PostgreSQL

Concluído

Este exercício leva você pelo processo de criação e configuração de um serviço Web baseado em .js Express que fornece acesso ao Banco de Dados do Azure para PostgreSQL.

Neste exercício, irá:

  • Crie um aplicativo Web Node.js Express de exemplo.
  • Conecte o aplicativo Web Node.js Express ao Banco de Dados do Azure para PostgreSQL.
  • Configure as rotas Node.js Express para acessar o Banco de Dados do Azure para PostgreSQL.
  • Valide a funcionalidade do serviço Web Node.js Express.

Pré-requisitos

Para realizar este exercício, você precisa:

  • Uma subscrição do Azure.
  • Uma conta Microsoft ou uma conta Microsoft Entra com a função de Administrador Global no inquilino do Microsoft Entra associada à subscrição do Azure e à função de Proprietário ou Colaborador na subscrição do Azure.
  • Ter concluído o primeiro exercício deste módulo. Você usará o banco de dados PostgreSQL do Azure criado e configurado nesse exercício.

Criar um aplicativo Web Node.js Express de exemplo

Você começará criando um aplicativo Web Node.js Express de exemplo e aplicará a ele alterações incrementais para implementar a funcionalidade desejada.

  1. Se necessário, a partir do seu computador, inicie um navegador da Web, navegue até o portal do Azure e entre para acessar a assinatura do Azure que você usou no primeiro exercício deste módulo.

  2. No portal do Azure, inicie uma sessão Bash no Cloud Shell selecionando seu ícone na barra de ferramentas ao lado da caixa de texto de pesquisa.

  3. Na sessão Bash no painel Cloud Shell , execute os seguintes comandos para inicializar um projeto Node.js em um novo diretório:

    mkdir -p cna-express && cd cna-express
    npm init -y
    

    Nota

    Isso cria um package.json, que contém todas as dependências para o projeto.

  4. Execute o seguinte comando para adicionar Express.js como dependência do projeto:

    npm install express
    
  5. Execute o seguinte comando para criar um arquivo chamado index.js na pasta can-express :

    touch ./index.js
    
  6. Execute o seguinte comando para abrir o índice de arquivo recém-criado.js no editor de códigos:

    code index.js
    
  7. Use o editor de código para adicionar ao arquivo .js índice o seguinte conteúdo e salve o arquivo:

    const express = require('express')
    const port = process.env.PORT || 8080
    const app = express()
    app.use(express.json());
    app.listen(port, () => console.log(`Sample app is listening on port ${port}!`))
    

    Nota

    Para salvar um arquivo no editor de códigos, use a combinação de teclas ctrl+s . Para fechar o painel do editor, use a combinação de teclas ctrl+q ou o menu no lado direito do painel.

    O script invoca o aplicativo, configurando-o para escutar na porta TCP 8080 e aceitar o corpo formatado em JSON de solicitações HTTP. A partir do Express 4.16+, app.use(express.json()) é necessário para análise JSON.

    O uso de process.env.PORT é específico para contêineres no Serviço de Aplicativo do Azure, que define a variável de ambiente PORT no contêiner Node.js e envia as solicitações de entrada para esse número de porta. Para receber as solicitações, seu aplicativo deve ouvir essa porta usando process.env.PORT (daí o uso de const port = process.env.PORT || 8080).

    Nota

    Você usará o Serviço de Aplicativo do Azure neste exercício para facilitar o teste da funcionalidade Node.js Express. Você também pode colocar o aplicativo em contêineres e implantá-lo usando Kubernetes e AKS, como demonstrado em um módulo anterior.

  8. Para permitir que o script seja executado, use o editor de código para modificar o arquivo package.json gerado automaticamente substituindo seu conteúdo existente pelo seguinte conteúdo:

    {
      "name": "node-express",
      "version": "1.0.0",
      "description": "Node.js express sample",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "nodemon index.js"
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "body-parser": "^1.19.0",
        "express": "^4.17.1",
        "http": "0.0.0",
        "morgan": "^1.10.0"
      },
      "devDependencies": {
        "nodemon": "^2.0.2"
      }
    }
    

Conectar o aplicativo Web Node.js Express ao Banco de Dados do Azure para PostgreSQL

Em seguida, você configurará seu aplicativo Web Node.js Express recém-criado para se conectar ao banco de dados cnainventory criado no exercício anterior deste módulo. Para fazer isso, você usará Sequelize, que é uma biblioteca JavaScript popular que fornece a funcionalidade Mapeador de Relação de Objeto, permitindo mapear construções programáticas no esquema de banco de dados correspondente.

  1. No seu computador, na janela do navegador da Web que exibe o portal do Azure, dentro da sessão Bash no painel do Cloud Shell , execute o seguinte comando para adicionar o Sequelize e os pacotes específicos do PostgreSQL correspondentes ao seu projeto:

    npm i sequelize pg pg-hstore
    
  2. Para aproveitar esses novos recursos, use o editor de código para adicionar a seguinte linha ao início do arquivo .js índice:

    const Sequelize = require('sequelize')
    
  3. Para estabelecer uma conexão com o banco de dados, você precisa adicionar uma cadeia de conexão no formato específico do Sequalize ao arquivo index.js seguindo a linha adicionada na etapa anterior. Substitua o espaço reservado <server_name> pelo nome do Banco de Dados do Azure para servidor PostgreSQL provisionado no exercício anterior:

    const sequelize = new Sequelize('postgres://Student%40<server_name>:Pa55w0rd1234@<server_name>.postgres.database.azure.com:5432/cnainventory')
    

    Nota

    O uso de %40 como caractere de escape entre o nome de usuário e o nome do servidor é específico para cadeias de conexão do Banco de Dados do Azure para PostgreSQL.

  4. Com o pacote Sequelize incluído como um requisito e a cadeia de conexão configurada, agora você pode estabelecer uma conexão com o banco de dados cnainventory adicionando o seguinte código ao arquivo index.js após o que você adicionou na etapa anterior:

    sequelize
    .authenticate()
    .then(() => {
       console.log('Connection has been established successfully.');
    })
    .catch(err => {
       console.error('Unable to connect to the database:', err);
    });
    
  5. Para facilitar as operações na tabela de inventário que você criou no exercício anterior, você precisa adicionar ao arquivo index.js, após o código adicionado na etapa anterior, uma definição específica de Sequelize correspondente ao formato da tabela, conforme abaixo:

    const Inventory = sequelize.define('inventory', {
       id: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true },
       name: { type: Sequelize.STRING, allowNull: false },
       quantity: { type: Sequelize.INTEGER },
       date: { type: Sequelize.DATEONLY, defaultValue: Sequelize.NOW }
    }, {
       freezeTableName: true,
       timestamps: false
    });
    

    Nota

    A timestamps: false opção é necessária para excluir do escopo das operações de banco de dados um conjunto de colunas relacionadas ao tempo, que, neste caso, não existem. A freezeTableName: true opção desativa o comportamento padrão de Sequelize, que transforma automaticamente todos os nomes de modelo em plural.

Configurar rotas Node.js Express para acesso ao Banco de Dados do Azure para PostgreSQL

Agora você está pronto para configurar as rotas que fornecerão acesso de leitura e gravação à tabela de inventário no banco de dados cnainventory hospedado pelo Banco de Dados do Azure para o servidor PostgreSQL. Para simplificar, você implementará apenas duas rotas, mas o procedimento para configurar outras rotas se assemelhará muito à implementação pela qual você passará nesta tarefa. A primeira rota permitirá que você adicione itens de inventário individuais invocando uma solicitação HTTP POST com os valores de item de inventário incluídos no corpo da solicitação, enquanto a segunda rota processará solicitações HTTP GET, retornando um item de inventário com base no valor de seu atributo id .

  1. No seu computador, na janela do navegador da Web que exibe o portal do Azure, na sessão Bash no painel do Cloud Shell , use o editor de código para adicionar o seguinte conteúdo ao final do arquivo .js índice:

    app.post('/inventory', async (req, res) => {
    try {
       const newItem = new Inventory(req.body)
       await newItem.save()
       res.json({ inventory: newItem })
    } catch(error) {
       console.error(error)
    }})
    

    Nota

    Essa parte do script gerencia as solicitações HTTP POST, adicionando uma linha à tabela de inventário que é preenchida com os valores dos atributos id, name e quantity incluídos no corpo da solicitação. O valor do atributo date é calculado automaticamente com base na data atual. A operação retorna os valores recém-adicionados como uma confirmação da operação bem-sucedida.

  2. No editor de códigos, adicione o seguinte conteúdo ao arquivo index.js seguindo o script adicionado na etapa anterior:

    app.get('/inventory/:id', async (req, res) => {
       const id = req.params.id
       try {
          const inventory = await Inventory.findAll({
          attributes: ['id', 'name', 'quantity', 'date'],
          where: {
             id: id
          }})
          res.json({ inventory })
       } catch(error) {
           console.error(error)
    }})
    

    Nota

    Esta parte do script gerencia as solicitações HTTP GET, retornando os valores dos atributos id, name, quantity e date com base no valor de id incluído na solicitação.

    Nota

    Isso produz um script totalmente funcional no seguinte formato (se você pretende copiar esse código, certifique-se de substituir cada ocorrência do nome pelo nome do cnapostgresqldb seu servidor PostgreSQL):

    const Sequelize = require('sequelize')
    const sequelize = new Sequelize('postgres://Student%40postgresql-ek.postgres.database.azure.com:Pa55w0rd1234@postgresql-ek.postgres.database.azure.com:5432/cnainventory')
    sequelize
    .authenticate()
    .then(() => {
       console.log('Connection has been established successfully.');
    })
    .catch(err => {
       console.error('Unable to connect to the database:', err);
    });
    const Inventory = sequelize.define('inventory', {
       id: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true },
       name: { type: Sequelize.STRING, allowNull: false },
       quantity: { type: Sequelize.INTEGER },
       date: { type: Sequelize.DATEONLY, defaultValue: Sequelize.NOW }
    }, {
       freezeTableName: true,
       timestamps: false
    });
    const express = require('express')
    const port = process.env.PORT || 8080
    const app = express()
    app.use(express.json());
    app.listen(port, () => console.log(`Sample app is listening on port ${port}!`))
    app.post('/inventory', async (req, res) => {
    try {
       const newItem = new Inventory(req.body)
       await newItem.save()
       res.json({ inventory: newItem })
    } catch(error) {
       console.error(error)
    }})
    app.get('/inventory/:id', async (req, res) => {
       const id = req.params.id
       try {
      const inventory = await Inventory.findAll({
          attributes: ['id', 'name', 'quantity', 'date'],
          where: {
             id: id
          }})
          res.json({ inventory })
       } catch(error) {
           console.error(error)
    }})
    

Validar a funcionalidade do serviço Web Node.js Express

Você finalmente está pronto para testar a funcionalidade do seu serviço Web. Você pode conteinerizá-lo neste momento, mas, por uma questão de simplicidade, implantá-lo-á em um Serviço de Aplicativo do Azure. Isso fornecerá uma maneira rápida de validar sua funcionalidade e garantir que a conteinerização seja uma opção viável.

  1. Na janela do navegador da Web que exibe o portal do Azure, na sessão Bash no painel do Cloud Shell, execute os seguintes comandos para criar um grupo de recursos que hospedará o aplicativo Web do Azure, no qual você implantará o aplicativo Node.js Express:

    RG1NAME=postgresql-db-RG
    LOCATION=$(az group show --resource-group $RG1NAME --query location --output tsv)
    RG2NAME=cna-express-RG
    az group create --name $RG2NAME --location $LOCATION
    
  2. Execute os seguintes comandos para criar um plano do Serviço de Aplicativo do Azure de camada gratuita que hospedará o novo aplicativo Web do Azure:

    SPNAME=express-sp
    az appservice plan create --name $SPNAME --resource-group $RG2NAME --sku F1 --is-linux
    
  3. Execute os seguintes comandos para criar o novo aplicativo Web do Azure baseado .js em nó e implantar o código nele:

    WEBAPPNAME=express$RANDOM$RANDOM
    az webapp create --name $WEBAPPNAME --resource-group $RG2NAME --plan $SPNAME --runtime "NODE|12-lts"
    
    cd ~/cna-express
    git config --global user.email "user1@adatum.com"
    git config --global user.name "Adatum User1"
    git init
    git add -A
    git commit -m "Initial Commit"
    
    DEPLOYMENTUSER=m03User$RANDOM
    DEPLOYMENTPASS=m03Pass$RANDOM$RANDOM
    az webapp deployment user set --user-name $DEPLOYMENTUSER --password $DEPLOYMENTPASS
    
    echo $DEPLOYMENTUSER
    echo $DEPLOYMENTPASS
    
    RG2NAME=cna-express-RG
    WEBAPPNAME=$(az webapp list --resource-group $RG2NAME --query "[0].name" --output tsv)
    DEPLOYMENTURL=$(az webapp deployment source config-local-git --name $WEBAPPNAME --resource-group $RG2NAME --output tsv)
    
    git remote add azure $DEPLOYMENTURL
    
    git checkout -b master
    git commit -a -m "test"
    git push --set-upstream azure master
    

    Nota

    Quando for solicitada uma senha, digite a senha exibida seguindo o echo $DEPLOYMENTPASS comando.

    Nota

    Ignore mensagens informando que a ramificação principal já existe ou que nada foi confirmado.

  4. Execute os seguintes comandos para validar o roteamento HTTP POST do aplicativo Node.js Express:

    RG2NAME=cna-express-RG
    WEBAPPNAME=$(az webapp list --resource-group $RG2NAME --query "[0].name" --output tsv)
    curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"id":3,"name":"ice cream","quantity":50}' \
    http://$WEBAPPNAME.azurewebsites.net/inventory
    

    Nota

    O comando deve retornar os valores das entradas da linha da tabela recém-adicionada, incluindo a data gerada automaticamente. Pode levar de um a dois minutos para que o comando retorne os valores de saída.

  5. Para validar o roteamento HTTP GET do aplicativo Node.js Express, no navegador da Web que exibe o painel Cloud Shell, abra outra guia, navegue até o portal do Azure e use a caixa de texto Pesquisar recursos, serviços e documentos para pesquisar o aplicativo Web do Serviço de Aplicativo que você implantou. Navegue até a folha Visão geral, identifique o valor da propriedade URL, acrescente a cadeia de caracteres a esse valor de URL, abra outra guia na mesma janela do navegador e navegue até a cadeia /inventory/3 de caracteres de URL recém-construída para exibir a página da Web correspondente.

    Nota

    A página deve exibir as propriedades do item que você adicionou à tabela de inventário do banco de dados cnainventory na etapa anterior.

Resultados

Parabéns! Você concluiu o segundo exercício deste módulo. Neste exercício, você criou e configurou um serviço Web baseado no Express.js que fornece acesso ao Banco de Dados do Azure para PostgreSQL. Os recursos que você implantou neste exercício serão necessários para concluir com êxito o próximo exercício neste módulo.