Tutorial: Criar uma aplicação Web Node.js com o SDK JavaScript para gerir uma API para conta NoSQL no Azure Cosmos DB

APLICA-SE A: NoSQL

Enquanto programador, poderá ter aplicações que utilizam dados de documentos NoSQL. Pode utilizar uma API para a conta NoSQL no Azure Cosmos DB para armazenar e aceder a estes dados do documento. Este tutorial Node.js mostra-lhe como armazenar e aceder a dados a partir de uma API para conta NoSQL no Azure Cosmos DB. O tutorial utiliza uma aplicação Node.js Express alojada na funcionalidade Aplicações Web do Microsoft Serviço de Aplicações do Azure. Neste tutorial, vai criar uma aplicação baseada na Web (aplicação Todo) que lhe permite criar, obter e concluir tarefas. As tarefas são armazenadas como documentos JSON no Azure Cosmos DB.

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

  • Configure uma conta do Azure Cosmos DB gratuita.
  • Crie e execute uma aplicação Web criada no SDK Node.js para criar uma base de dados e um contentor.
  • Adicione itens ao contentor.

Este tutorial utiliza o SDK JavaScript versão 3.0 e abrange as seguintes tarefas:

  • Criar uma conta do Azure Cosmos DB
  • Criar uma nova aplicação Node.js
  • Ligar a aplicação ao Azure Cosmos DB
  • Executar e implementar a aplicação no Azure

Pré-requisitos

Antes de seguir as instruções deste artigo, certifique-se de que tem os seguintes recursos:

Criar uma conta do Azure Cosmos DB

Comece por criar uma conta do Azure Cosmos DB. Se já tiver uma conta ou se utilizar o Emulador do Azure Cosmos DB para este tutorial, pode avançar para Criar uma nova aplicação Node.js.

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

  2. Procure 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 secção Azure Cosmos DB para NoSQL .

    O Azure Cosmos DB fornece várias APIs:

    • NoSQL, para dados de documentos
    • PostgreSQL
    • MongoDB, para dados de documentos
    • Apache Cassandra
    • Tabela
    • Apache Gremlin, para dados de gráficos

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

  4. Na página Criar Conta do Azure Cosmos DB , introduza as definições básicas para a nova conta do Azure Cosmos DB.

    Definição Valor Descrição
    Subscrição Nome da subscrição Selecione a subscrição do Azure que quer utilizar para esta conta do Azure Cosmos DB.
    Grupo de Recursos Nome do grupo de recursos Selecione um grupo de recursos ou selecione Criar novo e, em seguida, introduza um nome exclusivo para o novo grupo de recursos.
    Nome da Conta Um nome exclusivo Introduza um nome para identificar a sua conta do Azure Cosmos DB. Uma vez que documents.azure.com é anexado ao nome que indicar para criar o URI, utilize um nome exclusivo. O nome só pode conter letras minúsculas, números e o caráter de hífen (-). Tem de ter entre 3 e 44 carateres.
    Localização A região mais próxima dos seus utilizadores Selecione a localização geográfica para alojar a sua conta do Azure Cosmos DB. Utilize a localização mais próxima dos utilizadores para lhes dar o acesso mais rápido aos dados.
    Modo de capacidade Débito aprovisionado ou Sem servidor Selecione Débito aprovisionado para criar uma conta no modo de débito aprovisionado . Selecione Sem servidor para criar uma conta no modo sem servidor .
    Aplicar o desconto de escalão gratuito do Azure Cosmos DB Aplicar ou Não aplicar Com o escalão gratuito do Azure Cosmos DB, obtém gratuitamente as primeiras 1000 RU/s e 25 GB de armazenamento numa conta. Saiba mais sobre o escalão gratuito.
    Limitar débito total da conta Selecionado ou não Limite a quantidade total de débito que pode ser aprovisionada nesta conta. Este limite impede custos inesperados relacionados com o débito aprovisionado. Pode atualizar ou remover este limite após a criação da sua conta.

    Pode ter até uma conta do Azure Cosmos DB de escalão gratuito por subscrição do Azure e tem de optar ativamente por participar ao criar a conta. Se não vir a opção para aplicar o desconto de escalão gratuito, outra conta na subscrição já foi ativada com o escalão gratuito.

    Captura de ecrã a mostrar a página Criar Conta do Azure Cosmos DB.

    Nota

    As seguintes opções não estão disponíveis se selecionar Sem servidor como modo de Capacidade:

    • Aplicar Desconto de Escalão Gratuito
    • Limitar débito total da conta
  5. No separador Distribuição Global , configure os seguintes detalhes. Pode deixar os valores predefinidos para este início rápido:

    Definição Valor Descrição
    Redundância Geográfica Desativar Ative ou desative a distribuição global na sua conta ao emparelhar a região com uma região de par. Pode adicionar mais regiões à sua conta mais tarde.
    Escritas de várias regiões Desativar A capacidade de escrita de várias regiões permite-lhe tirar partido do débito aprovisionado para as suas bases de dados e contentores em todo o mundo.
    Zonas de Disponibilidade Desativar Zonas de Disponibilidade ajudar a melhorar ainda mais a disponibilidade e a resiliência da sua aplicação.

    Nota

    As seguintes opções não estão disponíveis se selecionar Sem servidor como o modo de Capacidade na página Básicas anterior:

    • Georredundância
    • Escritas de várias regiões
  6. Opcionalmente, pode configurar mais detalhes nos seguintes separadores:

    • Rede. Configurar o acesso a partir de uma rede virtual.
    • Política de Cópia de Segurança. Configure uma política de cópia de segurança periódica ou contínua .
    • Encriptação. Utilize uma chave gerida pelo serviço ou uma chave gerida pelo cliente.
    • Etiquetas. As etiquetas são pares de nomes/valores que lhe permitem categorizar recursos e ver a faturação consolidada ao aplicar a mesma etiqueta a vários recursos e grupos de recursos.
  7. Selecione Rever + criar.

  8. Reveja as definições da conta e, em seguida, selecione Criar. A criação da conta demora alguns minutos. Aguarde até que a página do portal apresente A implementação está concluída.

    Captura de ecrã a mostrar que a implementação está concluída.

  9. Selecione Ir para recurso para aceder à página da conta do Azure Cosmos DB.

    Captura de ecrã a mostrar a página da conta do Azure Cosmos DB.

Aceda à página da conta do Azure Cosmos DB e selecione Chaves. Copie os valores a utilizar na aplicação Web que criar a seguir.

Captura de ecrã do portal do Azure com o botão Chaves realçado na página da conta do Azure Cosmos DB

Criar uma nova aplicação Node.js

Agora, saiba como criar um projeto de Hello World Node.js básico com a arquitetura Express.

  1. Abra o seu terminal favorito, como a linha de comandos Node.js.

  2. Navegue para o diretório no qual pretende armazenar a nova aplicação.

  3. Utilizar o Express generator para gerar uma nova aplicação designada todo.

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

    cd todo
    npm install
    
  5. Execute a nova aplicação.

    npm start
    
  6. Para ver a sua nova aplicação num browser, aceda a http://localhost:3000.

    Captura de ecrã da aplicação Hello World numa janela do browser.

    Pare a aplicação com CTRL+C na janela do terminal e selecione y para terminar a tarefa de lote.

Instalar os módulos necessários

O ficheiro package.json é um dos ficheiros criados na raiz do projeto. Este ficheiro contém uma lista de outros módulos necessários para a sua aplicação Node.js. Quando implementar esta aplicação no Azure, este ficheiro servirá para determinar quais os módulos que devem estar instalados no Azure para suportar a sua aplicação. Instale mais dois pacotes para este tutorial.

  1. Instale o módulo @azure/cosmos através do npm.

    npm install @azure/cosmos
    

Ligar a aplicação Node.js ao Azure Cosmos DB

Depois de concluir a configuração inicial, saiba como escrever o código que a aplicação todo necessita para comunicar com o Azure Cosmos DB.

Criar o modelo

  1. Na raiz do diretório do projeto, crie um novo diretório com o nome modelos.

  2. No diretório modelos, crie um novo ficheiro designado taskDao.js. Este ficheiro contém o código necessário para criar a base de dados e o contentor. Também define métodos para ler, atualizar, criar e localizar tarefas no Azure Cosmos DB.

  3. Copie o seguinte código para o ficheiro 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. Guarde e feche o ficheiro taskDao.js.

Criar o controlador

  1. No diretório rotas do seu projeto, crie um novo ficheiro designado tasklist.js.

  2. Adicione o seguinte código ao tasklist.js. Este código carrega os módulos CosmosClient e async, que são utilizados por tasklist.js. Este código também define a classe TaskList, que é transmitida como uma instância do objeto TaskDao que definimos 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. Guarde e feche o ficheiro tasklist.js.

Adicionar config.js

  1. Na raiz do diretório do projeto, crie um ficheiro novo designado config.js.

  2. Adicione o seguinte código ao ficheiro config.js. Este código define os parâmetros e os valores da configuração necessários para a nossa aplicação.

    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 ficheiro config.js, atualize os valores de HOST e AUTH_KEY com os valores encontrados na página Chaves da sua conta do Azure Cosmos DB no portal do Azure.

  4. Guarde e feche o ficheiro config.js.

Modificar app.js

  1. No diretório do projeto, abra o ficheiro app.js. Este ficheiro foi criado anteriormente, aquando da criação da aplicação Web Express.

  2. Adicione o seguinte código ao ficheiro app.js. Este código define o ficheiro de configuração a ser utilizado e carrega os valores para algumas variáveis que irá utilizar nas secções seguintes.

     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, guarde e feche o ficheiro app.js.

Criar uma interface de utilizador

Agora, crie a interface de utilizador para que um utilizador possa interagir com a aplicação. A aplicação Express que criou nas secções anteriores utiliza o Jade como motor de visualização.

  1. O ficheiro layout.jade no diretório vistas é utilizado como um modelo global para outros ficheiros .jade. Neste passo, vai modificá-lo para utilizar o Twitter Bootstrap, que é um toolkit utilizado para criar um site.

  2. Abra o ficheiro 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')
    

    Este código indica ao motor jade para compor algum HTML para a aplicação e cria um bloco chamado conteúdo onde pode fornecer o esquema para as páginas de conteúdo. Guarde e feche o ficheiro layout.jade.

  3. Abra o ficheiro index.jade , a vista utilizada pela aplicação. Substitua o conteúdo do ficheiro pelo seguinte código:

    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
    

Este código expande o esquema e fornece conteúdo para o marcador de posição de conteúdo que viu no ficheiro layout.jade . Nesse esquema, criou dois formulários HTML.

O primeiro formulário contém uma tabela para os seus dados e um botão que lhe permite atualizar itens ao publicar no método /completeTask do controlador.

O segundo formulário contém dois campos de entrada e um botão que lhe permite criar um novo item ao publicar no método /addtask do controlador, que é tudo o que precisa para que a aplicação funcione.

Executar a sua aplicação localmente

Depois de criar a aplicação, pode executá-la localmente com os seguintes passos:

  1. Para testar a aplicação no seu computador local, execute npm start no terminal para iniciar a aplicação e, em seguida, atualize a http://localhost:3000 página. A página deverá agora ter o seguinte aspeto de captura de ecrã:

    Captura de ecrã da aplicação A Minha Lista de Todoes num browser.

    Dica

    Se receber um erro sobre o avanço no ficheiro layout.jade ou no ficheiro index.jade , certifique-se de que as duas primeiras linhas em ambos os ficheiros são justificadas sem espaços. Se existirem espaços antes das duas primeiras linhas, remova-os, guarde ambos os ficheiros e, em seguida, atualize a janela do browser.

  2. Utilize os campos Nome do Item e Categoria de Item para introduzir uma nova tarefa e, em seguida, selecione Adicionar Item para criar um documento no Azure Cosmos DB com essas propriedades.

  3. A página é atualizada para apresentar o item criado recentemente na lista ToDo.

    Captura de ecrã da aplicação com um novo item na lista ToDo.

  4. Para concluir uma tarefa, selecione a caixa de verificação na coluna Concluir e, em seguida, selecione Atualizar tarefas para atualizar o documento que já criou e removê-lo da vista.

  5. Para parar a aplicação, prima CTRL+C na janela do terminal e, em seguida, selecione y para terminar a tarefa de lote.

Implementar a sua aplicação no Serviço de Aplicações

Depois de a sua aplicação ter êxito localmente, pode implementá-la no Serviço de Aplicações do Azure. No terminal, certifique-se de que está no diretório da aplicação todo . Implemente o código na pasta local (todo) com 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 carateres válidos são a-z, 0-9 e -). Um bom padrão é utilizar uma combinação do nome da sua empresa e de um identificador de aplicação. Para saber mais sobre a implementação de aplicações, veja Node.js implementação de aplicações no Azure.

O comando pode demorar alguns minutos a concluir. O comando fornece mensagens sobre como criar o grupo de recursos, o plano Serviço de Aplicações e o recurso da aplicação, configurando o registo e efetuando a implementação ZIP. O comando fornece estas mensagens durante a execução. Em seguida, dá-lhe um URL para iniciar a aplicação em http://<app-name>.azurewebsites.net, que é o URL da aplicação no Azure.

Limpar os recursos

Quando estes recursos já não forem necessários, pode eliminar o grupo de recursos, a conta do Azure Cosmos DB e todos os recursos relacionados. Para tal, selecione o grupo de recursos que utilizou para a conta do Azure Cosmos DB, selecione Eliminar e, em seguida, confirme o nome do grupo de recursos a eliminar.

Passos seguintes

Pode utilizar informações sobre o cluster de bases de dados existentes para o planeamento de capacidade.