
Compartir:
Zoe Mithaug es becaria de Relaciones con Desarrolladores en Vonage. Es estudiante de cuarto año de licenciatura en la Universidad de Florida.
Le apasionan la programación, el desarrollo de software, el desarrollo de videojuegos, la animación y el diseño digital.
Reserva de horas de oficina con Node.js y la API Messages API de Vonage
Tiempo de lectura: 8 minutos
Introducción
En este tutorial, crearemos una aplicación web que permita a los estudiantes reservar horarios de oficina con sus profesores. Una vez que se reserva una hora de oficina, el estudiante recibirá un mensaje de texto confirmando la reserva a través de Vonage Messages API.
Lo construiremos utilizando Node.js, Express, SQLite y la API Messages API de Vonage. El repositorio repositorio de GitHub para este proyecto también está disponible.
Creación de una aplicación web
Página de inicio
Necesitaremos crear tres plantillas HTML para que sirvan como formulario de entrada (la página de inicio), página de error y página de confirmación. Después de crear estas plantillas, pasaremos al "motor" que impulsa esta aplicación web en Node.js. Para empezar, vamos a empezar con la creación de una página de inicio donde un usuario puede introducir información como su nombre, su número de teléfono, la fecha de su elección, su preferencia de tiempo, y cualquier nota o comentario que tienen que utilizar un formulario web básico. Este formulario se enviará a nuestra aplicación web para su procesamiento.
Empecemos creando un archivo index.html que incluya el título de nuestra página, importe nuestro estilo CSS y un formulario web básico para recopilar la información de los estudiantes. Debería tener este aspecto:
<html>
<head>
<title>Office Hours Reservation</title>
<link type="text/css" rel="stylesheet" href="/assets/indexstyles.css" />
<link
rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css"
/>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
</head>
<body>
<h1>Office Hours Reservation Form</h1>
<div id="statusdiv">Current Status</div>
<form
id="scheduleform"
name="scheduleform"
method="post"
action="/schedule"
>
<div id="FormInfo">
<div class="FormTextBox">
<div id="alignRight">Select Date for Reservation:</div>
<div>
<script>
$(function () {
$("#datepicker").datepicker();
});
</script>
<input
type="text"
name="AppointmentDate"
value="7/15/2022"
id="datepicker"
/>
</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Select Professor:</div>
<div>
<select name="ProfessorName">
<option value="Professor Nimoy">Professor Nimoy</option>
<option value="Dr. Rory">Dr. Rory</option>
<option value="Professor Amanda">Professor Amanda</option>
<option value="Professor Dwane">Professor Dwane</option>
<option value="Dr. Zach">Dr. Zach</option>
</select>
</div>
</div>
<!--FormTextBox-->
<div class="FormTextAreaBox">
<div>Choose Appointment Time:</div>
<div>
<label>
<input type="radio" name="AppointmentTime" value="8" /> 8:00 AM
</label>
<label>
<input type="radio" name="AppointmentTime" value="9" /> 9:00 AM
</label>
<label>
<input type="radio" name="AppointmentTime" value="10" /> 10:00 AM
</label>
<label>
<input type="radio" name="AppointmentTime" value="11" /> 11:00 AM
</label>
</div>
</div>
<!--FormTextAreaBox-->
<div class="FormTextBox">
<div id="alignRight">Student First Name:</div>
<div>
<input
type="text"
name="studentfirstname"
id="studentfirstname_id"
/>
</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Student Last Name:</div>
<div>
<input type="text" name="studentlastname" id="studentlastname_id" />
</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Student Phone Number:</div>
<div>
<input
type="text"
name="studentphonenumber"
id="studentphonenumber_id"
/>
</div>
</div>
<!--FormTextBox-->
<div class="FormTextAreaBox">
<div>Comments, Questions, Notes...</div>
<div>
<textarea
name="studentnotes"
id="studentnotes_id"
style="width: 300px; height: 100px"
>
</textarea>
</div>
</div>
<!--FormTextAreaBox-->
<div style="text-align: center">
<button type="submit" name="booknowbutton" class="BigButton">
Book Now
</button>
</div>
</div>
<!--FormInfo-->
</form>
</body>
</html>En nuestro ejemplo, incluimos un campo de entrada de fecha de reserva, un grupo de radio de hora de reserva, un cuadro desplegable para elegir opciones de profesor, junto con el nombre del alumno, el teléfono móvil del alumno y un campo de comentarios.

Por último, cree un botón de envío llamado "Reservar ahora" para enviar el contenido del formulario. Estamos publicando este formulario en nuestro servidor web en esta URL: /postschedule, de la que hablaremos más adelante en nuestro tutorial.
Página de error
En el caso de que el usuario introduzca datos no válidos, o se produzca un error al procesar la petición, mostraremos una página HTML de error informando al usuario de lo que ha ido mal. Esta es una simple página HTML que será procesada por Node.js y mostrará variables específicas del lado del servidor (a través de Nunjucks) que establezcamos dependiendo del problema que se haya producido. Este es un ejemplo del aspecto de nuestra página error.html página:
<html>
<head>
<title>There is an Error processing your request</title>
<link type="text/css" rel="stylesheet" href="/assets/errorstyles.css" />
<link
rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css"
/>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
</head>
<body>
<h1>There was an Error processing your request</h1>
<div
id="statusdiv"
>
Please correct the following:
<ul>
{{ErrorMessage}}
</ul>
</div>
<form
id="scheduleform"
name="scheduleform"
method="post"
action="/schedule"
>
<div id="FormInfo">
<div class="FormTextBox">
<div id="alignRight">Date for Reservation:</div>
<div class="readonlydata">{{AppointmentDate}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Appointment Time:</div>
<div class="readonlydata">{{AppointmentTime}}</div>
</div>
<!--FormTextAreaBox-->
<div class="FormTextBox">
<div id="alignRight">Professor:</div>
<div class="readonlydata">{{ProfessorName}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Student Name:</div>
<div class="readonlydata">{{StudentName}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Student Phone Number:</div>
<div class="readonlydata">{{StudentPhoneNumber}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextAreaBox">
<div>Comments, Questions, Notes...</div>
<div class="readonlydata">{{StudentNotes}}</div>
</div>
<!--FormTextAreaBox-->
<div id="returnButton">
<a href="/" class="BigButton"> Return to Reservation Form </a>
</div>
</div>
<!--FormInfo-->
</form>
</body>
</html>Nuestra página de error renderizada tendrá este aspecto:
Error page
Las variables encerradas entre corchetes dobles, por ejemplo: {{AppointmentDate}}son las variables del lado del servidor que se envían a través de Node.js. Discutiremos esta configuración más adelante en este tutorial. Finalmente, crearemos un botón de retorno. Este botón devolvería al usuario a la página de inicio si se produjera un error al procesar su solicitud de reserva.
Página de confirmación
Ahora que tenemos una respuesta de error, también debemos configurar una respuesta de confirmación. Esta página se mostrará sólo si la solicitud tiene éxito. Del mismo modo, esta página mostrará toda la información introducida por el usuario. Para empezar, crearemos un archivo confirmation.html y lo configuraremos de forma similar a nuestro archivo error.html con variables del lado del servidor (Nunjucks). He aquí un ejemplo de lo que nuestra confirmation.html página:
<html>
<head>
<title>Your Reservation has been confirmed</title>
<link
type="text/css"
rel="stylesheet"
href="/assets/confirmationstyles.css"
/>
<link
rel="stylesheet"
href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css"
/>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
</head>
<body>
<h1>Your Reservation has been confirmed</h1>
<form
id="scheduleform"
name="scheduleform"
method="post"
action="/schedule"
>
<div id="FormInfo">
<div class="FormTextBox">
<div id="alignRight">Date for Reservation:</div>
<div class="readonlydata">{{AppointmentDate}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Appointment Time:</div>
<div class="readonlydata">{{AppointmentTime}}</div>
</div>
<!--FormTextAreaBox-->
<div class="FormTextBox">
<div id="alignRight">Professor:</div>
<div class="readonlydata">{{ProfessorName}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Student Name:</div>
<div class="readonlydata">{{StudentName}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextBox">
<div id="alignRight">Student Phone Number:</div>
<div class="readonlydata">{{StudentPhoneNumber}}</div>
</div>
<!--FormTextBox-->
<div class="FormTextAreaBox">
<div>Comments, Questions, Notes...</div>
<div class="readonlydata">{{StudentNotes}}</div>
</div>
<!--FormTextAreaBox-->
<div id="returnButton">
<a href="/" class="BigButton"> Return to Reservation Form </a>
</div>
</div>
<!--FormInfo-->
</form>
</body>
</html>Nuestra página de Confirmación renderizada tendrá este aspecto:
Confirmation page
Tenga en cuenta que nuestras variables del lado del servidor se derivarán del formulario enviado por el estudiante, y son las siguientes: AppointmentDate, AppointmentTime, ProfessorName, StudentName, StudentPhoneNumbery StudentNotes. Por último, crearemos un botón de retorno. Este botón devolverá al usuario a la página de inicio si desea crear otra solicitud de reserva.
Backend
Opción Mecánica: Dotenv
Antes de que podamos comenzar la implementación de nuestro backend, debemos crear un archivo llamado .env. Este archivo es extremadamente importante ya que almacena nuestro API Secret y API Key privados. Estas variables nos permiten enviar nuestro texto de confirmación usando la API de Messages API de Vonage. Comience por crear un nuevo archivo llamado .env y colócalo en el directorio raíz de tu proyecto. Ahora, agrega las siguientes variables con la información específica de tu Account de Vonage: VONAGE_API_KEY, VONAGE_API_SECRETy FROM_PHONE_NUMBER.
Configuración de Node.js como servidor de aplicaciones web
Para completar nuestra aplicación web, añadiremos funcionalidad a nuestros archivos HTML utilizando Node.js, Express y SQLite. Para simplificar, colocaremos toda la funcionalidad de nuestra aplicación web en un único archivo llamado index.js. Una vez que tengamos Node.js instalado correctamente en nuestro sistema, necesitaremos añadir algunos paquetes más a la configuración: Express, Nunjucks, Fetch y SQLite.
npm install express
npm install nunjucks
npm install node-fetch
npm install sqlite3
npm install dotenv
npm install @vonage/server-sdkConfiguramos nuestro archivo index.js para utilizar las librerías recién instaladas y dar a nuestra aplicación la capacidad de servir páginas web en el puerto 3000. El inicio de nuestro archivo index.js tiene el siguiente aspecto:
require("dotenv").config();
const express = require("express");
const nunjucks = require("nunjucks");
const webserver = express();
const Vonage = require("@vonage/server-sdk");
const SMS = require("@vonage/server-sdk/lib/Messages/SMS");
const fetch = (...args) =>
import("node-fetch").then(({ default: fetch }) => fetch(...args));
webserver.use("/assets", express.static("assets"));
nunjucks.configure("html", { autoescape: false, express: webserver });
webserver.use(express.json());
webserver.use(express.urlencoded({ extended: true }));
// Global database
const sqlite3 = require("sqlite3").verbose();
const db = new sqlite3.Database("reservations.db");
const vonage = new Vonage({
apiKey: process.env.VONAGE_API_KEY,
apiSecret: process.env.VONAGE_API_SECRET,
});
webserver.listen(3000);Algunas notas sobre el código:
Estamos llamando al servidor web de la instancia Express
Colocamos nuestros tres archivos HTML (
index.html,error.html,confirmation.html) en un subdirectorio llamado HTML que Nunjucks está configurado para mirar.Hemos configurado SQLite para utilizar una base de datos llamada
reservations.dbque estará en el directorio raíz de esta aplicación web.Estamos ocultando las variables Clave de API y Secreto de API que nos proporcionó la API de Messages API de Vonage en un archivo
.envpero deberás sustituir estas variables por tus propias credenciales seguras.
Estamos configurando el servidor web para que escuche las peticiones web en el puerto 3000. Esto significa que para ejecutar esta aplicación, tendrá que especificar este puerto, por ejemplo, http://localhost:3000.
Uso de Node.js como servidor de aplicaciones web
Nuestro código index.js código para proporcionar tres funciones:
Configurar la base de datos para almacenar las solicitudes de reserva (
reservations.db)Mostrar una página de inicio en la que un estudiante pueda enviar una solicitud de cita (
index.html)Procese la solicitud de reserva del estudiante enviada a
/scheduley, una vez revisado el envío, responder con éxito (confirmation.html) o error (error.html)
SetUpDatabase();
DisplayHomePage();
PostSchedule();
Configuración de la base de datos
En este proyecto, estamos utilizando SQLite como base de datos backend para almacenar nuestra información. Sin embargo, puedes utilizar cualquier base de datos que funcione con Node.js.
function SetUpDatabase() {
db.serialize(() => {
db.run(
"CREATE TABLE if not exists Appointments (appointmentdate text, appointmenttime text, professorname text, studentfirstname text, studentlastname text, studentphonenumber text, studentnotes text)"
);
});
}Algunas notas sobre esta función:
Se comprobará si existe una tabla de citas en la base de datos.
reservations.dbbase de datos; si la tabla no existe, la crearáDependiendo del sistema de base de datos que decidas utilizar con Node.js, querrás cambiar la fecha y la hora de la cita para que funcionen con las funciones datetime de ese motor
Configuración de la página de inicio
Nuestra función DisplayHomePage() simplemente escucha la petición en la raíz del directorio ('/') y luego renderiza nuestro archivo index.html que se encuentra en el directorio HTML. Recordará que ya hemos configurado el archivo index.html para que sea el formulario de reserva de horas de oficina.
function DisplayHomePage() {
// Displaying Homepage after reading an HTML file locally
webserver.get("/", function (req, res) {
res.render("index.html");
});
} Configuración de la función de planificación de contabilización
PostSchedule() es el caballo de batalla de nuestra aplicación web. Este proceso escuchará el /schedule y realizará una comprobación básica de errores de la entrada del usuario. Si los datos de envío pasan nuestro rudimentario proceso de comprobación de errores, guardaremos esta información en nuestra tabla de citas en la base de datos reservations.db base de datos. Luego, encapsularemos esta información en un objeto JSON que enviaremos a la API de Messages API de Vonage para enviar un mensaje de confirmación.
function PostSchedule() {
// POST /new Route Handler
webserver.post("/schedule", function (req, res) {
// Student info/variables collected from HTML form
let professorname = req.body.ProfessorName;
let appointmentdate = req.body.AppointmentDate;
let appointmenttime = req.body.AppointmentTime;
let studentfirstname = req.body.studentfirstname;
let studentlastname = req.body.studentlastname;
let studentphonenumber = req.body.studentphonenumber;
let studentnotes = req.body.studentnotes;
// Text message info sent to Student
let message =
"Dear " +
studentfirstname +
" " +
studentlastname +
"," +
" you have successfully booked your appointment! Here are your additional notes: " +
studentnotes;
let ValidationCheck = true; // Assume success, prove otherwise
let ErrorMessage = "";
if (appointmentdate == "") {
ValidationCheck = false;
ErrorMessage = ErrorMessage + "<li>Enter an appointment date</li>";
} else if (appointmenttime == "" || !appointmenttime) {
ValidationCheck = false;
ErrorMessage = ErrorMessage + "<li>Enter an appointment time</li>";
} else if (professorname == "") {
ValidationCheck = false;
ErrorMessage = ErrorMessage + "<li>Select a Professor</li>";
} else if (studentfirstname == "") {
ValidationCheck = false;
ErrorMessage = ErrorMessage + "<li>Enter a Student first name</li>";
} else if (studentlastname == "") {
ValidationCheck = false;
ErrorMessage = ErrorMessage + "<li>Enter a Student last name</li>";
} else if (studentphonenumber == "") {
ValidationCheck = false;
ErrorMessage = ErrorMessage + "<li>Enter a mobile phone number</li>";
}
if (ValidationCheck == false) {
res.render("error.html", {
ProfessorName: professorname,
StudentName: studentfirstname + " " + studentlastname,
AppointmentDate: appointmentdate,
AppointmentTime: appointmenttime,
StudentNotes: studentnotes,
StudentPhoneNumber: studentphonenumber,
ErrorMessage: ErrorMessage,
});
} else {Algunas notas sobre este código:
Nuestra instancia Express llamada servidor web está a la escucha de un mensaje enviado a
/scheduley sólo se ejecuta si se da esta condiciónHemos creado las siguientes variables Node.js a los correspondientes pares nombre/valor del formulario de solicitud HTML:
professorname = req.body.ProfessorName
appointmentdate = req.body.AppointmentDate
appointmenttime = req.body.AppointmentTime
studentfirstname = req.body.studentfirstname
studentlastname = req.body.studentlastname
studentphonenumber = req.body.studentphonenumber
studentnotes = req.body.studentnotesNuestra variable booleana
ValidationCheckcomprueba si hay datos de cadena vacíos y se establece en false en caso de fallo. Deberá realizar una comprobación de errores adicional para otros escenarios de datos erróneos, como fechas y horas de citas no válidasSi se produce un error, generamos la página
error.htmlque incluye la configuración de la variable Nunjucks{{ErrorMessage}}con una descripción del problemaEn
ValidationCheckéxito (devolviendo:true), continuaremos agregando los datos de la cita a la tabla de citas y enviaremos la confirmación de texto mediante la API de mensajería de Vonage.
Luego de la validación exitosa de la entrada, ahora encapsulamos el mensaje en un objeto JSON que enviaremos a Vonage. Creamos la instancia de la clase cliente de Vonage, la inicializamos con la clave y el secreto de la API de Vonage que agregaste previamente a tu archivo .env y las variables necesarias son el número de teléfono, el número de teléfono del destinatario, el texto del mensaje y nuestra clave y secreto de la API.
else {
vonage.messages.send(
new SMS(message, studentphonenumber, process.env.FROM_PHONE_NUMBER),
(err, data) => {
if (err) {
console.error(err);
} else {
console.log(data.message_uuid);
}
}
);
// Build SQL string --> insert string to add record to appointments table
let sqlstring =
"INSERT INTO Appointments (appointmentdate, appointmenttime, professorname, studentfirstname, studentlastname, studentphonenumber, studentnotes) " +
"VALUES (?, ?, ?, ?, ?, ?, ?)";
// Execute SQL string into database (Using paramaterized queries to prevent SQL injection)
db.run(
sqlstring,
appointmentdate,
appointmenttime,
professorname,
studentfirstname,
studentlastname,
studentphonenumber,
studentnotes
);
// For testing purposes query all records in appointments table and display to console
// The last record shown should be the record we just inserted
db.each(
"SELECT appointmentdate, appointmenttime, professorname, studentfirstname, studentlastname info FROM Appointments",
(err, row) => {
console.log(
row.appointmentdate +
": " +
row.appointmenttime +
":" +
row.professorname
);
}
);
res.render("confirmation.html", {
ProfessorName: professorname,
StudentName: studentfirstname + " " + studentlastname,
AppointmentDate: appointmentdate,
AppointmentTime: appointmenttime + ":00 AM",
StudentNotes: studentnotes,
StudentPhoneNumber: studentphonenumber,
});
}A continuación, construimos nuestra sentencia de inserción SQL utilizando las variables que establecimos desde el formulario de envío HTML, y ejecutamos esa sentencia utilizando la función db.run . Por último, mostramos la confirmation.html para que se muestren las variables Nunjucks.
Próximos pasos
La participación de la comunidad es siempre bienvenida. No dude en unirse a nosotros en GitHub y en Slack de la comunidad de Vonage o envíanos un mensaje en Twitter.
Compartir:
Zoe Mithaug es becaria de Relaciones con Desarrolladores en Vonage. Es estudiante de cuarto año de licenciatura en la Universidad de Florida.
Le apasionan la programación, el desarrollo de software, el desarrollo de videojuegos, la animación y el diseño digital.