Tutorial: Criar um aplicativo Web Node.js usando o SDK do JavaScript para gerenciar uma conta de API para NoSQL no Azure Cosmos DB

APLICA-SE A: NoSQL

Como um desenvolvedor, você pode ter aplicativos que usam dados de documentos NoSQL. Use uma conta de API para NoSQL no Azure Cosmos DB para armazenar e acessar esses dados de documentos. Este tutorial Node.js mostra como armazenar e acessar dados de uma conta da API para NoSQL no Azure Cosmos DB. O tutorial usa um aplicativo Node.js Express hospedado no recurso Aplicativo Web do Serviço de Aplicativo do Microsoft Azure. Neste tutorial, você criará um aplicativo baseado na Web (aplicativo Todo) que permite criar, recuperar e concluir tarefas. As tarefas são armazenadas como documentos JSON no Azure Cosmos DB.

Este tutorial demonstra como criar uma conta de API para NoSQL no Azure Cosmos DB usando o portal do Azure. Sem um cartão de crédito ou uma assinatura do Azure, você pode:

  • Configurar uma conta do Azure Cosmos DB gratuita.
  • Construir e executar um aplicativo Web que é construído sobre o SDK do Node.js para criar um banco de dados e um contêiner.
  • Adicionar itens ao contêiner.

Este tutorial usa o SDK do JavaScript versão 3.0 e aborda as seguintes tarefas:

  • Criar uma conta do Azure Cosmos DB
  • Criar um novo aplicativo do Node.js
  • Conectar o aplicativo ao Azure Cosmos DB
  • Executar e implantar o aplicativo no Azure

Pré-requisitos

Antes de seguir as instruções deste artigo, verifique se você tem os seguintes recursos:

Criar uma conta do Azure Cosmos DB

Comece criando uma conta do Azure Cosmos DB. Se você já tiver uma conta ou se usar o Emulador do Azure Cosmos DB para este tutorial, pule para Criar um novo aplicativo do Node.js.

  1. No menu do portal do Azure ou na Home page, selecione Criar um recurso.

  2. Pesquise por Azure Cosmos DB. Selecione Criar>Azure Cosmos DB.

  3. Na página Criar uma conta do Azure Cosmos DB, selecione a opção Criar na seção Azure Cosmos DB for NoSQL.

    O Azure Cosmos DB fornece várias APIs:

    • NoSQL, para dados do documento
    • PostgreSQL
    • MongoDB, para dados do documento
    • Apache Cassandra
    • Tabela
    • Apache Gremlin, para dados do grafo

    Para saber mais sobre a API para NoSQL, confira Bem-vindo(a) ao Azure Cosmos DB.

  4. Na página Criar uma Conta do Azure Cosmos DB, insira as configurações básicas da nova conta do Azure Cosmos DB.

    Configuração Valor Descrição
    Subscription Nome da assinatura Selecione a assinatura do Azure que você deseja usar para essa conta do Azure Cosmos DB.
    Grupo de recursos Nome do grupo de recursos Selecione um grupo de recursos ou selecione Criar novo, então insira um nome exclusivo para o novo grupo de recursos.
    Nome da Conta Um nome exclusivo Insira um nome para identificar a conta do Azure Cosmos DB. Já que documents.Azure.com é acrescentado ao nome que você fornece para criar o URI, use um nome exclusivo. O nome pode conter apenas letras minúsculas, números e o caractere de hífen (-). Deve ter de 3 a 44 caracteres.
    Location A região mais próxima dos usuários Selecione uma localização geográfica para hospedar a sua conta do Azure Cosmos DB. Use a localização mais próxima dos usuários para fornecer a eles acesso mais rápido aos dados.
    Modo de capacidade Taxa de transferência provisionada ou sem servidor Selecione Taxa de transferência provisionada para criar uma conta no modo taxa de transferência provisionada. Selecione Sem servidor para criar uma conta no modo sem servidor.
    Aplicar o desconto por nível gratuito do Azure Cosmos DB Aplicar ou Não aplicar Com a camada gratuita do Azure Cosmos DB, você recebe os primeiros 1000 RU/s e 25 GB de armazenamento sem custos em uma conta. Saiba mais sobre o nível gratuito.
    Limitar a taxa de transferência total da conta Selecionado ou não Limite a quantidade total da taxa de transferência que pode ser provisionada nessa conta. Esse limite impede encargos inesperados relacionados à taxa de transferência provisionada. Você pode atualizar ou remover esse limite depois que sua conta for criada.

    Você pode ter até uma conta gratuita do Azure Cosmos DB por assinatura do Azure e deve aceitar ao criar a conta. Se você não vê a opção de aplicar o desconto por nível gratuito, outra conta da assinatura já foi habilitada com o nível gratuito.

    Captura de tela mostrando a página Criar Conta do Azure Cosmos DB.

    Observação

    As seguintes opções não estarão disponíveis se você selecionar Sem servidor como Modo de capacidade:

    • Aplicar desconto por nível gratuito
    • Limitar a taxa de transferência total da conta
  5. Na guia Distribuição global, configure os detalhes a seguir. Para este início rápido, é possível usar os valores padrão:

    Configuração Valor Descrição
    Redundância geográfica Desabilitar Habilite ou desabilite a distribuição global em sua conta emparelhando sua região com uma região de par. Você poderá adicionar mais regiões à sua conta posteriormente.
    Gravações de várias regiões Desabilitar A capacidade de gravação de várias regiões permite que você aproveite a taxa de transferência provisionada para seus bancos de dados e contêineres em todo o mundo.
    Zonas de Disponibilidades Desabilitar As Zonas de Disponibilidade ajudam a aprimorar a disponibilidade e a resiliência do seu aplicativo.

    Observação

    As seguintes opções não estarão disponíveis se você selecionar Sem servidor como Modo de capacidade na página anterior Noções básicas:

    • Redundância geográfica
    • Gravações de várias regiões
  6. Opcionalmente, você pode configurar mais detalhes nas seguintes guias:

    • Redes. Configure o acesso a partir de uma rede virtual.
    • Política de Backup. Configure uma política de backup periódica ou contínua.
    • Criptografia. Use uma chave gerenciada pelo serviço ou uma chave gerenciada pelo cliente.
    • Marcas. Marcas são pares nome/valor que permitem categorizar recursos e exibir a cobrança consolidada por meio da aplicação da mesma marca a vários recursos e grupos de recursos.
  7. Selecione Examinar + criar.

  8. Examine as configurações da conta e selecione Criar. São necessários alguns minutos para criar a conta. Aguarde até que a página do portal exiba Sua implantação está concluída.

    Captura de tela mostrando que sua implantação está concluída.

  9. Selecione Ir para recurso para ir para a página da conta do Azure Cosmos DB.

    Captura de tela mostrando a página da conta do Azure Cosmos DB.

Vá até a página da conta do Azure Cosmos DB e selecione Chaves. Copie os valores a serem usados no aplicativo Web que será criado em seguida.

Captura de tela do Portal do Azure com o botão Chaves realçado na página de conta do Azure Cosmos DB

Criar um novo aplicativo do Node.js

Agora, aprenda a criar um projeto Olá, Mundo em Node.js básico usando a estrutura Express.

  1. Abra seu terminal favorito, como o prompt de comando do Node.js.

  2. Navegue até o diretório no qual você deseja armazenar o novo aplicativo.

  3. Use o gerador expresso para gerar um novo aplicativo chamado tarefas.

    express todo
    
  4. Abra o novo diretório todo e instale as dependências.

    cd todo
    npm install
    
  5. Execute o novo aplicativo.

    npm start
    
  6. Para exibir seu novo aplicativo em um navegador, acesse http://localhost:3000.

    Captura de tela do aplicativo Olá, Mundo em uma janela de navegador.

    Interrompa o aplicativo usando CTRL+C na janela do terminal e marque y para finalizar o trabalho em lotes.

Instalar os módulos necessários

O arquivo package.json é um dos arquivos criados na raiz do projeto. Esse arquivo contém uma lista de outros módulos que são necessários para seu aplicativo Node.js. Ao implantar esse aplicativo no Azure, esse arquivo será usado para determinar quais módulos precisam ser instalados no Azure para dar suporte ao seu aplicativo. Instale mais dois pacotes para este tutorial.

  1. Instale o módulo @azure/cosmos via npm.

    npm install @azure/cosmos
    

Conectar o aplicativo do Node.js ao Azure Cosmos DB

Depois de concluir a instalação e a configuração iniciais, saiba como escrever o código necessário para que o aplicativo todo se comunique com o Azure Cosmos DB.

Criar o modelo

  1. Na raiz do diretório do projeto, crie um novo diretório chamado modelos.

  2. No diretório models, criar um novo arquivo chamado taskDao.js. Esse arquivo contém o código necessário para criar o banco de dados e o contêiner. Ele também define métodos para ler, atualizar, criar e localizar as tarefas no Azure Cosmos DB.

  3. Copie o código a seguir para o arquivo taskDao.js:

     // @ts-check
     const CosmosClient = require('@azure/cosmos').CosmosClient
     const debug = require('debug')('todo:taskDao')
    
     // For simplicity we'll set a constant partition key
     const partitionKey = undefined
     class TaskDao {
       /**
        * Manages reading, adding, and updating Tasks in Azure Cosmos DB
        * @param {CosmosClient} cosmosClient
        * @param {string} databaseId
        * @param {string} containerId
        */
       constructor(cosmosClient, databaseId, containerId) {
         this.client = cosmosClient
         this.databaseId = databaseId
         this.collectionId = containerId
    
         this.database = null
         this.container = null
       }
    
       async init() {
         debug('Setting up the database...')
         const dbResponse = await this.client.databases.createIfNotExists({
           id: this.databaseId
         })
         this.database = dbResponse.database
         debug('Setting up the database...done!')
         debug('Setting up the container...')
         const coResponse = await this.database.containers.createIfNotExists({
           id: this.collectionId
         })
         this.container = coResponse.container
         debug('Setting up the container...done!')
       }
    
       async find(querySpec) {
         debug('Querying for items from the database')
         if (!this.container) {
           throw new Error('Collection is not initialized.')
         }
         const { resources } = await this.container.items.query(querySpec).fetchAll()
         return resources
       }
    
       async addItem(item) {
         debug('Adding an item to the database')
         item.date = Date.now()
         item.completed = false
         const { resource: doc } = await this.container.items.create(item)
         return doc
       }
    
       async updateItem(itemId) {
         debug('Update an item in the database')
         const doc = await this.getItem(itemId)
         doc.completed = true
    
         const { resource: replaced } = await this.container
           .item(itemId, partitionKey)
           .replace(doc)
         return replaced
       }
    
       async getItem(itemId) {
         debug('Getting an item from the database')
         const { resource } = await this.container.item(itemId, partitionKey).read()
         return resource
       }
     }
    
     module.exports = TaskDao
    
  4. Salve e feche o arquivo taskDao.js .

Criar o controlador

  1. No diretório rotas do projeto, crie um novo arquivo chamado tasklist.js.

  2. Adicione os seguintes códigos ao tasklist.js. Esse código carrega os módulos CosmosClient e assíncrono que são usados pelo tasklist.js. Ele também define a classe TaskList que é transmitida a uma instância do objeto TaskDao definido anteriormente:

     const TaskDao = require("../models/TaskDao");
    
     class TaskList {
       /**
        * Handles the various APIs for displaying and managing tasks
        * @param {TaskDao} taskDao
        */
       constructor(taskDao) {
         this.taskDao = taskDao;
       }
       async showTasks(req, res) {
         const querySpec = {
           query: "SELECT * FROM root r WHERE r.completed=@completed",
           parameters: [
             {
               name: "@completed",
               value: false
             }
           ]
         };
    
         const items = await this.taskDao.find(querySpec);
         res.render("index", {
           title: "My ToDo List ",
           tasks: items
         });
       }
    
       async addTask(req, res) {
         const item = req.body;
    
         await this.taskDao.addItem(item);
         res.redirect("/");
       }
    
       async completeTask(req, res) {
         const completedTasks = Object.keys(req.body);
         const tasks = [];
    
         completedTasks.forEach(task => {
           tasks.push(this.taskDao.updateItem(task));
         });
    
         await Promise.all(tasks);
    
         res.redirect("/");
       }
     }
    
     module.exports = TaskList;
    
  3. Salve e feche o arquivo tasklist.js .

Adicionar config.js

  1. Na raiz do diretório do projeto, crie um novo arquivo chamado config.js.

  2. Adicione o código a seguir ao arquivo config.js. Esse código define as configurações e valores necessários para nosso aplicativo.

    const config = {};
    
    config.host = process.env.HOST || "[the endpoint URI of your Azure Cosmos DB account]";
    config.authKey =
      process.env.AUTH_KEY || "[the PRIMARY KEY value of your Azure Cosmos DB account";
    config.databaseId = "ToDoList";
    config.containerId = "Items";
    
    if (config.host.includes("https://localhost:")) {
      console.log("Local environment detected");
      console.log("WARNING: Disabled checking of self-signed certs. Do not have this code in production.");
      process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
      console.log(`Go to http://localhost:${process.env.PORT || '3000'} to try the sample.`);
    }
    
    module.exports = config;
    
  3. No arquivo config.js, atualize os valores de HOST e de AUTH_KEY usando os valores encontrados na página Chaves de sua conta do Azure Cosmos DB no portal do Azure.

  4. Salve e feche o arquivo config.js .

Modificar app.js

  1. No diretório do projeto, abra o arquivo app.js . Esse arquivo foi criado anteriormente, quando o aplicativo Web Express foi criado.

  2. Adicione o código a seguir ao arquivo app.js. Esse código define o arquivo de configuração a ser usado e carrega os valores para algumas variáveis que você usará nas próximas seções.

     const CosmosClient = require('@azure/cosmos').CosmosClient
     const config = require('./config')
     const TaskList = require('./routes/tasklist')
     const TaskDao = require('./models/taskDao')
    
     const express = require('express')
     const path = require('path')
     const logger = require('morgan')
     const cookieParser = require('cookie-parser')
     const bodyParser = require('body-parser')
    
     const app = express()
    
     // view engine setup
     app.set('views', path.join(__dirname, 'views'))
     app.set('view engine', 'jade')
    
     // uncomment after placing your favicon in /public
     //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
     app.use(logger('dev'))
     app.use(bodyParser.json())
     app.use(bodyParser.urlencoded({ extended: false }))
     app.use(cookieParser())
     app.use(express.static(path.join(__dirname, 'public')))
    
     //Todo App:
     const cosmosClient = new CosmosClient({
       endpoint: config.host,
       key: config.authKey
     })
     const taskDao = new TaskDao(cosmosClient, config.databaseId, config.containerId)
     const taskList = new TaskList(taskDao)
     taskDao
       .init(err => {
         console.error(err)
       })
       .catch(err => {
         console.error(err)
         console.error(
           'Shutting down because there was an error settinig up the database.'
         )
         process.exit(1)
       })
    
     app.get('/', (req, res, next) => taskList.showTasks(req, res).catch(next))
     app.post('/addtask', (req, res, next) => taskList.addTask(req, res).catch(next))
     app.post('/completetask', (req, res, next) =>
       taskList.completeTask(req, res).catch(next)
     )
     app.set('view engine', 'jade')
    
     // catch 404 and forward to error handler
     app.use(function(req, res, next) {
       const err = new Error('Not Found')
       err.status = 404
       next(err)
     })
    
     // error handler
     app.use(function(err, req, res, next) {
       // set locals, only providing error in development
       res.locals.message = err.message
       res.locals.error = req.app.get('env') === 'development' ? err : {}
    
       // render the error page
       res.status(err.status || 500)
       res.render('error')
     })
    
     module.exports = app
    
  3. Por fim, salve e feche o arquivo app.js.

Criar uma interface do usuário

Agora crie a interface do usuário para que um usuário possa interagir com o aplicativo. O aplicativo Express que você criou na seção anterior usa Jade como o mecanismo de exibição.

  1. O arquivo layout.jade no diretório views é usado como um modelo global para outros arquivos .jade. Nesta etapa, você o modifica para usar Twitter Bootstrap, um kit de ferramentas usado para projetar sites da Web.

  2. Abra o arquivo layout.jade encontrado na pasta views e substitua o conteúdo pelo seguinte código:

    doctype html
    html
      head
        title= title
        link(rel='stylesheet', href='//ajax.aspnetcdn.com/ajax/bootstrap/3.3.2/css/bootstrap.min.css')
        link(rel='stylesheet', href='/stylesheets/style.css')
      body
        nav.navbar.navbar-inverse.navbar-fixed-top
          div.navbar-header
            a.navbar-brand(href='#') My Tasks
        block content
        script(src='//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.2.min.js')
        script(src='//ajax.aspnetcdn.com/ajax/bootstrap/3.3.2/bootstrap.min.js')
    

    Esse código instrui o mecanismo Jade a renderizar um HTML para o aplicativo e cria um bloco chamado content em que podemos fornecer o layout para as páginas de conteúdo. Salve e feche o arquivo layout.jade .

  3. Abra o arquivo index.jade, a exibição usada pelo aplicativo. Substitua o conteúdo do arquivo pelo código a seguir:

    extends layout
    block content
         h1 #{title}
         br
    
         form(action="/completetask", method="post")
          table.table.table-striped.table-bordered
             tr
               td Name
               td Category
               td Date
               td Complete
             if (typeof tasks === "undefined")
               tr
                 td
             else
               each task in tasks
                 tr
                   td #{task.name}
                   td #{task.category}
                   - var date  = new Date(task.date);
                   - var day   = date.getDate();
                   - var month = date.getMonth() + 1;
                   - var year  = date.getFullYear();
                   td #{month + "/" + day + "/" + year}
                   td
                    if(task.completed) 
                     input(type="checkbox", name="#{task.id}", value="#{!task.completed}", checked=task.completed)
                    else
                     input(type="checkbox", name="#{task.id}", value="#{!task.completed}", checked=task.completed)
           button.btn.btn-primary(type="submit") Update tasks
         hr
         form.well(action="/addtask", method="post")
           label Item Name:
           input(name="name", type="textbox")
           label Item Category:
           input(name="category", type="textbox")
           br
           button.btn(type="submit") Add item
    

Esse código estende o layout e fornece conteúdo para o espaço reservado content que você viu no arquivo layout.jade. Naquele layout, você criou dois formulários HTML.

O primeiro formulário contém uma tabela para nossos dados e um botão que permite atualizar itens ao ser lançado o método /completeTask do controlador.

O segundo formulário contém dois campos de entrada e um botão que permite criar um novo item postando no método /addtask do controlador, que é tudo o que você precisa para que o aplicativo funcione.

Execute o seu aplicativo localmente

Depois de criar o aplicativo, você pode executá-lo localmente usando as seguintes etapas:

  1. Para testar o aplicativo no computador local, execute npm start no terminal para iniciar o aplicativo e atualize a página http://localhost:3000. A página deve se parecer com a captura de tela abaixo:

    Captura de tela do aplicativo Minha Lista de Tarefas em um navegador.

    Dica

    Se receber um erro sobre o recuo no arquivo layout.jade ou o arquivo index.jade, verifique se as duas primeiras linhas em ambos os arquivos estão justificadas à esquerda, sem espaços. Se houver espaços antes das duas primeiras linhas, remova-os, salve os dois arquivos e atualize a janela do navegador.

  2. Use os campos Nome do Item e Categoria do Item para inserir uma nova tarefa e selecione Adicionar Item para criar um documento no Azure Cosmos DB com essas propriedades.

  3. A página atualiza para exibir o item recém-criado na lista de Tarefas.

    Captura de tela do aplicativo com um novo item na lista de Tarefas.

  4. Para concluir uma tarefa, selecione a caixa marcar na coluna Concluir e selecione Atualizar tarefas para atualizar o documento que você já criou e removê-lo do modo de exibição.

  5. Para interromper o aplicativo, pressione CTRL+C na janela do terminal e selecione y para finalizar o trabalho em lotes.

Implantar seu aplicativo no Serviço de Aplicativo

Depois que seu aplicativo for bem-sucedido localmente, você poderá implantá-lo no Serviço de Aplicativo do Azure. No terminal, verifique se você está no diretório de aplicativos todo. Implante o código em sua pasta local (todo) usando o seguinte comando az webapp up:

az webapp up --sku F1 --name <app-name>

Substitua <app_name> por um nome exclusivo em todo o Azure (os caracteres válidos são a-z, 0-9 e -). Um bom padrão é usar uma combinação do nome da empresa e um identificador de aplicativo. Para saber mais sobre a implantação do aplicativo, confira Implantação de aplicativo Node.js no Azure.

O comando pode levar alguns minutos para ser concluído. O comando envia mensagens sobre como criar o grupo de recursos, o plano do Serviço de Aplicativo, o recurso de aplicativo, como configurar o registro em log, bem como executar a implantação zip. O comando fornece essas mensagens durante a execução. Em seguida, ele fornece uma URL para iniciar o aplicativo em http://<app-name>.azurewebsites.net, que é a URL do aplicativo no Azure.

Limpar os recursos

Quando esses recursos já não forem necessários, você poderá excluir o grupo de recursos, a conta do Azure Cosmos DB e todos os recursos relacionados. Para fazer isso, selecione o grupo de recursos que você usou para a conta do Azure Cosmos DB, selecione Excluir e, em seguida, confirme o nome do grupo de recursos a ser excluído.

Próximas etapas

Você pode usar informações sobre o cluster de banco de dados existente para fazer isso.