Tutorial: Compilación de una aplicación web de Node.js mediante el SDK de JavaScript para administrar una cuenta de la API de NoSQL en Azure Cosmos DB

SE APLICA A: NoSQL

Como desarrollador, puede que tenga aplicaciones que usan datos de documentos NoSQL. Puede usar una cuenta de la API de NoSQL en Azure Cosmos DB para almacenar los datos de este documento y acceder a ellos. En este tutorial de Node.js se muestra cómo almacenar datos y acceder a ellos desde una cuenta de API para NoSQL en Azure Cosmos DB. En el tutorial se usa una aplicación Node.js Express hospedada en la característica Web Apps de Microsoft Azure App Service. En este tutorial, creará una aplicación basada en web (aplicación de tareas pendientes), que le permite crear, recuperar y completar tareas. Las tareas se almacenan como documentos JSON en Azure Cosmos DB.

En este tutorial se muestra cómo crear una cuenta de la API de NoSQL en Azure Cosmos DB mediante Azure Portal. Sin una tarjeta de crédito o una suscripción de Azure, puede hacer lo siguiente:

En este tutorial se usa la versión 3.0 del SDK de JavaScript y se describen las siguientes tareas:

  • Creación de una cuenta de Azure Cosmos DB
  • Creación de una aplicación Node.js
  • Conexión de una aplicación a Azure Cosmos DB
  • Ejecución e implementación de la aplicación en Azure

Prerrequisitos

Antes de seguir las instrucciones del presente artículo, asegúrese de tener los siguientes recursos:

Creación de una cuenta de Azure Cosmos DB

Para comenzar, cree una cuenta de Azure Cosmos DB. Si ya tiene una cuenta o si usa el emulador de Azure Cosmos DB en este tutorial, puede ir directamente a la Creación de una nueva aplicación Node.js.

  1. En el menú de Azure Portal o en la página principal, seleccione Crear un recurso.

  2. Busque Azure Cosmos DB. Seleccione Crear>Azure Cosmos DB.

  3. En la página Crear una cuenta de Azure Cosmos DB, seleccione la opción Crear en la sección Azure Cosmos DB for NoSQL.

    Azure Cosmos DB proporciona varias API:

    • NoSQL, para datos de documento
    • PostgreSQL
    • MongoDB, para datos de documento
    • Apache Cassandra
    • Tabla
    • Apache Gremlin, para datos de grafo

    Para obtener más información sobre la API para NoSQL, consulte Bienvenido a Azure Cosmos DB.

  4. En la página Crear una cuenta de Azure Cosmos DB, especifique la configuración básica de la nueva cuenta de Azure Cosmos DB.

    Configuración Valor Descripción
    Subscription Nombre de suscripción Seleccione la suscripción de Azure que quiere usar para esta cuenta de Azure Cosmos DB.
    Grupo de recursos Definición de un nombre de grupo de recursos Seleccione un grupo de recursos o seleccione Crear nuevo y escriba un nombre único para el grupo de recursos nuevo.
    Nombre de cuenta Un nombre único Escriba un nombre para identificar la cuenta de Azure Cosmos DB. Dado que documents.azure.com se anexa al nombre que se proporciona para crear el identificador URI, debe usar un nombre único. El nombre solo puede contener letras minúsculas, números y el carácter de guion (-). Debe tener entre 3 y 44 caracteres.
    Location Región más cercana a los usuarios Seleccione una ubicación geográfica para hospedar la cuenta de Azure Cosmos DB. Use la ubicación más cercana a los usuarios para que puedan acceder de la forma más rápida posible a los datos.
    Capacity mode (Modo de capacidad) Rendimiento aprovisionado o Sin servidor Seleccione Provisioned throughput (Rendimiento aprovisionado) para crear una cuenta en modo de rendimiento aprovisionado. Seleccione Serverless (Sin servidor) para crear una cuenta en modo sin servidor.
    Aplicar el descuento del nivel Gratis de Azure Cosmos DB Aplicar o No aplicar Con el nivel Gratis de Azure Cosmos DB, recibe los primeros 1000 RU/s y 25 GB de almacenamiento gratis en una cuenta. Más información acerca del nivel Gratis.
    Límite del rendimiento total de la cuenta Seleccionado o no Limite la cantidad total de rendimiento que se puede aprovisionar en esta cuenta. Este límite evita cargos inesperados relacionados con el rendimiento aprovisionado. Puede actualizar o quitar este límite después de crear la cuenta.

    Puede tener una cuenta de Azure Cosmos DB de nivel gratis por cada suscripción de Azure y debe optar por recibirla al crear la cuenta. Si no ve la opción para aplicar el descuento por nivel Gratis, significa que el nivel Gratis ya se habilitó en otra cuenta de la suscripción.

    Captura de pantalla que muestra la página Crear cuenta de Azure Cosmos DB.

    Nota

    Las siguientes opciones no están disponibles si selecciona Serverless (Sin servidor) en Capacity mode (Modo de capacidad):

    • Aplicación de descuento por nivel Gratis
    • Límite del rendimiento total de la cuenta
  5. En la pestaña Distribución global, configure los detalles siguientes. Puede dejar los valores predeterminados para este inicio rápido:

    Configuración Valor Descripción
    Redundancia geográfica Deshabilitar Habilite o deshabilite la distribución global en su cuenta. Para ello, debe emparejar su región con una región de par. Puede agregar más regiones a su cuenta más adelante.
    Escrituras en varias regiones Deshabilitar La funcionalidad de escrituras en varias regiones le permite aprovechar el rendimiento aprovisionado para sus bases de datos y contenedores de todo el mundo.
    Zonas de disponibilidad Deshabilitar Las zonas de disponibilidad le ayudan a mejorar aún más la disponibilidad y la resistencia de una aplicación.

    Nota

    Las siguientes opciones no están disponibles si selecciona Sin servidor en Modo de capacidad en la página anterior Básico:

    • Redundancia geográfica
    • Escrituras en varias regiones
  6. De manera opcional, puede configurar más detalles en las pestañas siguientes:

    • Funciones de red. Configure el acceso desde una red virtual.
    • Directiva de copia de seguridad. Configure una directiva de copia de seguridad periódica o continua.
    • Cifrado. Use una clave administrada por el servicio o una clave administrada por el cliente.
    • Etiquetas. Las etiquetas son pares nombre-valor que permiten categorizar los recursos y ver una facturación consolidada mediante la aplicación de la misma etiqueta en varios recursos y grupos de recursos.
  7. Seleccione Revisar + crear.

  8. Revise la configuración de la cuenta y seleccione Crear. La operación de creación de la cuenta tarda unos minutos. Espere hasta que la página del portal muestre Se completó la implementación .

    Captura de pantalla que muestra que se completó la implementación.

  9. Seleccione Ir al recurso para ir a la página de la cuenta de Azure Cosmos DB.

    Captura de pantalla que muestra la página de cuenta de Azure Cosmos DB.

Vaya a la página de la cuenta de Azure Cosmos DB y seleccione Claves. Copie los valores que se van a usar en la aplicación web que creará a continuación.

Captura de pantalla de Azure Portal con el botón Claves resaltado en la página de la cuenta de Azure Cosmos DB

Creación de una aplicación Node.js

Ahora, aprenderemos a crear un proyecto Node.js básico de Hola mundo usando el marco Express.

  1. Abra su terminal favorito como, por ejemplo, el símbolo del sistema de Node.js.

  2. Navegue hasta el directorio en el que desea almacenar la nueva aplicación.

  3. Use Express Generator para generar una nueva aplicación denominada todo.

    express todo
    
  4. Abra el directorio todo e instale las dependencias.

    cd todo
    npm install
    
  5. Ejecute la nueva aplicación.

    npm start
    
  6. Para ver la nueva aplicación en un explorador, vaya a http://localhost:3000.

    Captura de pantalla de la aplicación Hola mundo en una ventana del explorador.

    Para detener la aplicación, use CTRL+C en la ventana del terminal y seleccione y para finalizar el trabajo por lotes.

Instalación de los módulos necesarios

El archivo package.json es uno de los archivos creados en la raíz del proyecto. Este archivo contiene una lista de módulos adicionales necesarios para una aplicación Node.js. Cuando implemente esta aplicación en Azure, este archivo se usará para determinar qué módulos se deben instalar en Azure para ofrecer respaldo a su aplicación. Instale dos paquetes más para este tutorial.

  1. Instale el módulo @azure/cosmos mediante npm.

    npm install @azure/cosmos
    

Conexión de la aplicación Node.js a Azure Cosmos DB

Después de completar la configuración inicial y los ajustes, aprenda a escribir el código que requiere la aplicación de tareas pendientes para comunicarse con Azure Cosmos DB.

Creación del modelo

  1. En la raíz del directorio del proyecto, cree un nuevo directorio con el nombre models.

  2. En el directorio models, cree un archivo nuevo con el nombre taskDao.js. Este archivo contiene el código necesario para crear la base de datos y el contenedor. También define los métodos para leer, actualizar, crear y encontrar tareas en Azure Cosmos DB.

  3. Copie el código siguiente en el archivo 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 y cierre el archivo taskDao.js .

Crear el controlador

  1. En el directorio routes del nuevo proyecto, cree un nuevo archivo denominado tasklist.js.

  2. Agregue el siguiente código a tasklist.js. Este código carga los módulos CosmosClient y async, que utiliza tasklist.js. Este código también define la clase TaskList, que pasa como una instancia del 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 y cierre el archivo tasklist.js .

Agregar config.js

  1. En la raíz del directorio del proyecto, cree un nuevo archivo con el nombre config.js.

  2. Agregue el código siguiente al archivo config.js. Este código define las opciones de configuración y los valores necesarios para nuestra aplicación.

    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. En el archivo config.js, actualice los valores de HOST y AUTH_KEY con los valores de la página de Claves de la cuenta de Azure Cosmos DB en Azure Portal.

  4. Guarde y cierre el archivo config.js .

Modificar app.js

  1. En el directorio del proyecto, abra el archivo app.js . Este archivo se creó anteriormente, cuando se creó la aplicación web de Express.

  2. Agregue el código siguiente al archivo app.js. Este código define el archivo de configuración que se va a utilizar y carga los valores en algunas variables que se utilizarán en las secciones siguientes.

     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 último, guarde y cierre el archivo app.js.

Creación de una interfaz de usuario

Ahora vamos a crear la interfaz de usuario para que un usuario pueda interactuar con la aplicación. La aplicación Express que hemos creado en las secciones anteriores utiliza Jade como motor de vistas.

  1. El archivo layout.jade del directorio views se utiliza como plantilla global para otros archivos .jade. En este paso podrá modificarlo para utilizar Twitter Bootstrap, que es un kit de herramientas que se utiliza para diseñar sitios web.

  2. Abra el archivo layout.jade que se encuentra en la carpeta views y reemplace el contenido por el código siguiente:

    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 al motor Jade que represente HTML para nuestra aplicación y que cree un bloque llamado content donde podemos especificar el diseño de nuestras páginas de contenido. Guarde y cierre este archivo layout.jade.

  3. Abra el archivo index.jade, la vista usada por la aplicación. Reemplace el contenido del archivo por el código siguiente:

    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 amplía el diseño y proporciona contenido para el marcador de posición content que vimos anteriormente en el archivo layout.jade. En este diseño, hemos creado dos formularios HTML.

El primer formulario contiene una tabla para los datos y un botón que permite actualizar los elementos mediante la publicación en el método /completeTask del controlador.

El segundo formulario contiene dos campos de entrada y un botón que permite crear un nuevo elemento publicando en el método /addtask del controlador, que es todo lo que necesita para que la aplicación funcione.

Ejecución de la aplicación de forma local

Ahora que compiló la aplicación, puede ejecutarla localmente con los pasos siguientes:

  1. Para probar la aplicación en el equipo local, ejecute npm start en el terminal para iniciar la aplicación y, a continuación, actualice la página http://localhost:3000. La página ahora debería tener un aspecto similar al de la siguiente captura de pantalla:

    Captura de pantalla de la aplicación My Todo List en una ventana del explorador.

    Sugerencia

    Si recibe un error de la sangría en el archivo layout.jade o el archivo index.jade, asegúrese de que las dos primeras líneas de ambos archivos estén justificadas a la izquierda, sin espacios en blanco. Si hay espacios delante de las dos primeras líneas, quítelos, guarde ambos archivos y, a continuación, actualice la ventana del explorador.

  2. Use los campos Nombre de elemento y Categoría de elemento para escribir una nueva tarea y, a continuación, seleccione Agregar elemento para crear un documento en Azure Cosmos DB con esas propiedades.

  3. La página debería actualizarse para mostrar el elemento recién creado en la lista de tareas pendientes.

    Captura de pantalla de la aplicación con un nuevo elemento en la lista de tareas pendientes.

  4. Para completar una tarea, active la casilla de la columna Completar y, a continuación, seleccione Actualizar tareas para actualizar el documento que ya ha creado y quitarlo de la vista.

  5. Para detener la aplicación, presione CTRL+C en la ventana del terminal y, después, seleccione Y para finalizar el trabajo por lotes.

Implementación de la aplicación en App Service

Una vez que la aplicación de ejecuta correctamente de manera local, puede implementarla en Azure App Service. En el terminal, asegúrese de que se encuentra en el directorio todo de la aplicación. Implemente el código en la carpeta local (tareas pendientes) mediante el siguiente comando az webapp up:

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

Reemplace <app_name> por un nombre que sea único en todo Azure (los caracteres válidos son a-z, 0-9 y "-"). Un buen patrón es usar una combinación del nombre de la empresa y un identificador de la aplicación. Para obtener más información sobre la implementación de aplicaciones, consulte el artículo Implementación de aplicaciones de Node.js en Azure.

El comando puede tardar unos minutos en completarse. El comando proporciona mensajes sobre la creación del grupo de recursos, el plan de App Service y el recurso de la aplicación, la configuración del registro y la implementación del archivo ZIP. El comando proporciona estos mensajes mientras se ejecuta. A continuación, proporciona una dirección URL para iniciar la aplicación en http://<app-name>.azurewebsites.net, que es la dirección URL de la aplicación en Azure.

Limpieza de recursos

Cuando ya no necesite estos recursos, podrá eliminar el grupo de recursos, la cuenta de Azure Cosmos DB y todos los recursos relacionados. Para hacerlo, seleccione el grupo de recursos que usó en la cuenta de Azure Cosmos DB, seleccione Eliminar y confirme el nombre del grupo de recursos que se va a eliminar.

Pasos siguientes

Para ello, puede usar información sobre el clúster de bases de datos existente.