
Erstellen eines Terminplaners mit Node, Firebase und Vonage
Lesedauer: 12 Minuten
Einführung
In diesem Tutorial werden wir eine Terminplanungs-Webanwendung mit Node.js, Express, Firebase und der Vonage Messages API. Das GitHub-Repository für dieses Projekt ist ebenfalls verfügbar, Sie können es hier klonen.
Firebase einrichten
Um zu beginnen, erstellen wir ein neues Projekt in der Firebase-Konsole.
Klicken Sie auf
add a new projectGeben Sie Ihrem Projekt einen aussagekräftigen Namen, zum Beispiel
vonage appointment schedulerPrüfen Sie, ob Ihnen die eindeutige Kennung für Ihr Projekt gefällt (sie wird in Ihrer Echtzeit-Datenbank-URL, den Firebase Hosting-Subdomains und mehr verwendet. Sie kann nach der Projekterstellung nicht mehr geändert werden)
Klicken Sie auf die Schaltfläche, um fortzufahren
Console view with a text field to enter project and name and edit the project id
Wählen Sie aus, ob Sie die Analysefunktion aktivieren möchten. In diesem Lernprogramm werden wir das nicht tun
Klicken Sie auf die Schaltfläche, um das Projekt zu erstellen
Warten, bis das Projekt erstellt ist
Project being created
Sobald das Projekt fertig ist, klicken Sie auf "Weiter". Sie werden zur Konsolenansicht Ihres Projekts weitergeleitet
Legen Sie die Abrechnungsart fest, indem Sie auf das Zahnradsymbol klicken, gefolgt von Nutzung und Abrechnung, dann auf die Registerkarte Details & Einstellungen und ändern Sie den Plan zur Verwendung von Blaze. Dieser Abrechnungstarif ist erforderlich, wenn Sie eine Drittanbieter-API verwenden.
Firebase Tools CLI installieren
Installieren Sie in Ihrem Terminal die Firebase-Tools mit NPM, falls Sie sie nicht bereits haben, indem Sie Folgendes eingeben: npm install -g firebase-tools. Geben Sie anschließend firebase login ein. Daraufhin öffnet sich ein Fenster in Ihrem Browser, das Sie entweder automatisch authentifiziert (wenn Sie bereits angemeldet sind) oder Sie nach Ihren Anmeldedaten fragt. Sobald dies abgeschlossen ist, haben Sie die Firebase CLI installiert.
RealTime-Datenbank erstellen und einrichten
Nun ist es an der Zeit, die NoSQL-Datenbankinstanz zu erstellen, in der die Informationen zu den Terminen gespeichert werden sollen. Unsere App wird eine Ansicht enthalten, in der ein Benutzer Termine vereinbaren oder absagen kann. Wenn die Person, die mit der Ansicht interagiert, ein Termindatum und eine Uhrzeit auswählt, wird dieser Slot der Firebase RealTime Database hinzugefügt oder entfernt.
Klicken Sie im Menü der Firebase-Konsole unter Build auf "Realtime Database".
Button to create the database
Klicken Sie auf "Datenbank erstellen".
Wählen Sie den Speicherort der Echtzeitdatenbank, in der Ihre Daten gespeichert werden sollen, und klicken Sie auf
nextWählen Sie, ob Sie die Datenbank im gesperrt oder im Testmodus. In diesem Beispiel verwende ich den Testmodus
Klicken Sie auf
enable
Database created
Importieren der Datenbank JSON-Datei
Lassen Sie uns eine Beispieldatenbank importieren, die bereits einige zugewiesene Slots enthält und aus der Sie in Zukunft Slots hinzufügen und entfernen können. Sie können eine Datei namens myAppointments.json erstellen, die das JSON aus dem folgenden Ausschnitt enthält, und diese Datei dann über die Konsole importieren.
myAppointments.json
{
"myAppointments": {
"0": {
"date": "2021-06-01T09:00",
"userId": "1234abcd"
},
"new_activity_7kh3a3a3z": {
"date": "2023-06-01T08:50",
"userId": "_7kh3a3a3z"
},
"new_activity_etxen95x3": {
"date": "2021-06-01T08:40",
"userId": "_etxen95x3"
}
}
}
Import Database
Hinzufügen der Datenbankregeln
Die Firebase Realtime Database Rules bestimmen, wer auf Ihre Datenbank zugreifen darf, wie Ihre Indizes aufgebaut sind und wie Ihre Daten strukturiert sind.
In der Firebase-Konsole sehen Sie in der Ansicht der Echtzeit-Datenbank "Regeln", klicken Sie auf diese Registerkarte. Sie werden zu einem Bildschirm weitergeleitet, auf dem Sie Ihre Regeln bearbeiten können
Kopieren Sie die Regeln aus dem folgenden Codeschnipsel und fügen Sie sie in Ihre Konsole ein, um die
myAppointmentsSammlung zu indizieren durch dasdateFeld zu indizieren.Klicken Sie auf
Publish
{
"rules": {
".read": "now < 1643842800000", // 2022-2-3
".write": "now < 1643842800000", // 2022-2-3
"myAppointments": {
".indexOn": ["date"]
}
}
}
Edit Firebase Database Rules
Erstellen Sie die Projektstruktur
Am Ende dieses Tutorials wird Ihre Projektstruktur ungefähr so aussehen. In den folgenden Schritten werden wir die Dateien erstellen, die den Inhalt, das Erscheinungsbild und die Funktionen aufbauen und die von uns verwendeten Dienste verwalten.
Project Structure
Einrichtung
Erstellen Sie den Projektordner und
cdhinein:mkdir appointment-scheduler && cd appointment-schedulerNPM initialisieren :
npm init. Mit diesem Befehl werden Sie aufgefordert, Informationen über das Projekt hinzuzufügenInstallieren Sie die Abhängigkeiten:
npm install @vonage/server-sdk dotenv uuid express firebase-admin firebase-functionsTyp
firebase init. Da wir bereits ein Projekt im Dashboard erstellt haben, können SieUse an existing projectwählen, woraufhin Sie aufgefordert werden, das gewünschte Projekt auszuwählen. Sie können mein Beispiel mit meiner Projekt-ID sehenvonage-appointment-schedulerunten. Ich habe mich auch für dieRealtime DatabaseFunktion
Erstellen Sie den HTML-Inhalt
Wussten Sie, dass das HTML-Eingabeelement viele Optionen für die Auswahl von Datum und Uhrzeit bietet? Wir haben zum Beispiel: date, datetime-local, time. In diesem Lernprogramm werden wir <input type="datetime-local">. Dieser Ansatz ist vielleicht nicht so stabil wie die Verwendung der Datums- und Zeitbibliothek, da es zu einigen Unstimmigkeiten kommen kann, aber für den Zweck dieses Tutorials funktioniert er. Der Benutzer kann alle 5 Minuten Zeitfenster buchen, die auf 0 oder 5 enden, z.B. 18:00 ist buchbar, 18:01 nicht.
Erstellen Sie die
public/index.htmldie den Inhalt für die Ansicht zum Auswählen eines neuen Termins oder zum Stornieren von Terminen enthält, indem Sie den folgenden Codeschnipsel hinzufügen
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Appointment Scheduler</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="styles/styles.css" />
</head>
<body>
<main>
<h1>Appointment Scheduler</h1>
<!-- datepicker from html. Source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local -->
<form action="/appointment" method="POST">
<div>
<label for="slot">Choose your slot: </label>
<input
id="slot"
type="datetime-local"
name="slotdate"
min="2021-06-01T08:30"
max="2023-10-30T16:30"
step="300"
required
/>
<span class="validity"></span>
</div>
<div>
<label for="phonenumber">Your phone number:</label>
<input type="tel" id="phonenumber" name="phonenumber" required />
<span class="validity"></span>
</div>
<div>
<input type="submit" value="Book slot!" />
</div>
</form>
<form action="/cancelAppointment" method="POST">
<div>
<input type="text" name="code" placeholder="code" />
<input type="submit" value="Remove slot!" />
</div>
</form>
</main>
</body>
</html>
CSS-Styling hinzufügen
Für diese Demo-Webanwendung fügen wir einige Formatierungen hinzu, um den Inhalt auf der Seite zu zentrieren und ein rotes ✖ anzuzeigen, wenn die Eingabe ungültig ist, und ein ✓, wenn sie gültig ist.
Erstellen Sie die
public/styles.cssDateiFügen Sie den folgenden CSS-Code ein
body {
margin: auto;
width: 50%;
padding: 10px;
}
div {
margin-bottom: 10px;
display: flex;
align-items: center;
}
label {
display: inline-block;
width: 300px;
}
input:invalid+span:after {
content: '✖';
color: red;
padding-left: 5px;
}
input:valid+span:after {
content: '✓';
color: green;
padding-left: 5px;
} Erstellen Sie die Umgebungsvariablendatei
Erstellen Sie das
.envund füllen Sie sie mit den folgenden Informationen
Die
FIREBASE_DATABASE_URLkann in der Firebase-Konsole gefunden werdenDie
VONAGE_API_KEYund dieVONAGE_API_SECRETfinden Sie im Vonage DashboardDie
VONAGE_FROM_NUMBERenthält die Nummer, den Namen oder die Marke, die als Absender der Nachricht erscheinen wirdDie
VONAGE_TO_NUMBERist die Nummer, die die SMS-Nachrichten erhalten wird
Erstellen Sie die JavaScript-Dateiserver.js
Wir erstellen die server.js um Express mitzuteilen, wie die von der Benutzeroberfläche gestellten Anfragen zu behandeln sind. Ich werde Ihnen Schritt für Schritt zeigen, wie wir ihn erstellen. Die komplette Serverdatei finden Sie hier.
Unsere Webanwendung wird express verwenden und die statischen Dateien lesen, die wir zuvor im Ordner public Ordner.
Um die Abhängigkeiten und Importdateien hinzuzufügen, fügen Sie den folgenden Codeschnipsel in Ihr
script/server.js
// script/server.js
require('dotenv').config();
const express = require('express');
const app = require('express')();
const port = 3000; //setting the port to listen to as 3000
const admin = require('firebase-admin');
const Vonage = require('@vonage/server-sdk');
const SMS = require('@vonage/server-sdk/lib/Messages/SMS';
const { v4: uuidv4 } = require('uuid');
app.use(express.static('public'));
app.use(express.json());
app.use(express.urlencoded({ extended: true })); Hinzufügen des Service Accounts
Ein Firebase Service Account kann verwendet werden, um verschiedene Firebase Features zu authentifizieren; für unser Projekt werden wir das Firebase Admin SDK verwenden, um auf unsere Datenbank URL zuzugreifen.
Klicken Sie in der Firebase-Konsole auf das Zahnrad und wählen Sie die Registerkarte Service Account
Klicken Sie auf die Schaltfläche, um
generate keyFügen Sie die erzeugte Datei in das Stammverzeichnis Ihres Projekts ein und benennen Sie sie um in
serviceAccountKey.jsonKopieren Sie das Admin SDK-Konfigurations-Snippet und fügen Sie es in Ihr Projekt ein, wie Sie im folgenden Schritt dieses Tutorials sehen können, um Firebase zu initialisieren. Wir verwenden
${process.env.FIREBASE_DATABASE_URLzum Lesen der URL aus der.envDatei zu lesen, aber es ist die gleiche Datenbank-URL wie in der Firebase Admin SDK-Konfiguration.
Admin SDK configuration
Firebase initialisieren
Wir verwenden initializeApp um eine Firebase-App-Instanz zu erstellen und zu initialisieren, die die /myAppointments Firebase-Datenbankinstanz verwendet, die wir zuvor über die Firebase-Konsole erstellt und befüllt haben.
Fügen Sie den folgenden Codeschnipsel zu Ihrem
server.jsum Firebase zu initialisieren.
const serviceAccount = require('../serviceAccountKey.json');
// Initializes firebase
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: `${process.env.FIREBASE_DATABASE_URL}`,
});
// A Reference represents a specific location in your Database and can be
// used for reading or writing data to that Database location.
ref = admin.database().ref('/myAppointments'); Initialisieren des Vonage API-Objekts
Wir erstellen die Instanz der Vonage-Client-Klasse und initialisieren sie mit dem Vonage-API-Schlüssel und dem Geheimnis, die Sie zuvor in Ihre .env Datei hinzugefügt haben.
Fügen Sie den folgenden Codeschnipsel zu Ihrem
server.jsum Vonage hinzuzufügen.
const vonage = new Vonage({
apiKey: process.env.VONAGE_API_KEY,
apiSecret: process.env.VONAGE_API_SECRET,
}); Erstellen Sie die Funktion getDateTime()
Der HTML-Eingabetyp datetime-local ist formatiert als JJJJ-MM-TThh:mm. Wir werden also eine Funktion schreiben, die das Datum von der Stunde trennt, indem sie es an dem Zeichen T. Zum Beispiel im Beispiel 2018-06-12T19:30hätten wir dann 2018-06-12 für das Datum und 19:30 für die Stunde.
Fügen Sie den folgenden Codeschnipsel zu Ihrem
server.jshinzu, um diegetDateTime()Funktion
const getDateTime = (slot) => {
return slot.split('T');
};
Erstellen Sie die/appointment Endpunkt
Es ist an der Zeit, den /appointment Endpunkt zu erstellen, der die POST-Anfragen zur Erstellung eines Termins bearbeitet. Dieser Endpunkt prüft, ob der Termin verfügbar ist, fügt den Termin zur Firebase-Datenbank hinzu und sendet schließlich eine SMS-Bestätigung über die Vonage Messages API an das Telefon des Benutzers zurück.
Fügen Sie den folgenden Codeschnipsel in Ihr
server.jsum den/appointmentEndpunkt zu erstellen.
app.post('/appointment', async (request, response) => {
let phonenumber = request.body.phonenumber;
let slot = request.body.slotdate;
let [date, time] = getDateTime(slot);
// Checks if a slot is available
checkIfAvailable = async (slot) => {};
// Adds to Database
addToDatabase = () => {};
// Sends an SMS back to the user's phone using the Vonage Messages API
sendSMStoUser = async (code) => {};
});
Sie haben vielleicht bemerkt, dass ein Großteil der Funktionalität innerhalb des Request Handlers noch nicht implementiert wurde. Daher wollen wir nun die Stubs für die erforderlichen Funktionalitäten erweitern.
Slot-Verfügbarkeit prüfen
Diese Funktion überprüft, ob ein Slot verfügbar ist, indem sie prüft, ob der Slot bereits in der Datenbank existiert. Wir fragen ab ref.orderByChild('date'). Die Abfragen dürfen jeweils nur einen Schlüssel anfordern. Wir haben zuvor unseren Index über die .indexOn in den Firebase Rules definiert, um die Leistung zu verbessern. Und dann verwenden wir .once('value') um auf genau ein Ereignis des Wertes zu warten, und dann hört es auf zu warten.
Fügen Sie den folgenden Codeschnipsel in Ihr
server.jshinzu, um diecheckIfAvailable()Funktion
// Checks if a slot is available
checkIfAvailable = async (slot) => {
let snapshot = await ref.orderByChild('date').once('value');
let available = true;
snapshot.forEach((data) => {
let dataval = data.val();
for (let key in dataval) {
let datapoint = dataval[key];
if (slot === datapoint) {
available = false;
}
}
});
return available;
};
Den Slot zur Datenbank hinzufügen
Die folgende Funktion addToDatabase() fügt den Termin und einen Code in die Firebase-Datenbank ein. Dieser Code wird benötigt, um den Termin zu stornieren.
// Adds the slot to the database
addToDatabase = () => {
let code = uuidv4();
ref.child(code).set({
date: slot,
userId: code,
});
return code;
};
Senden Sie eine SMS mit den Termindaten
Sobald der Platz reserviert ist, wird eine SMS-Bestätigung an den Benutzer zurückgeschickt mit der Nachricht Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment. wie in der Funktion zu sehen ist sendSMStoUser().
Fügen Sie den folgenden Codeschnipsel in Ihr
server.jshinzu, um diesendSMStoUser()Funktion
// Sends an SMS back to the user's phone using the Vonage Messages API
sendSMStoUser = async (code) => {
const to = phonenumber;
const text = `Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment.`;
const result = await new Promise((resolve, reject) => {
vonage.messages.send(
new SMS(text, process.env.VONAGE_TO_NUMBER, "Vonage"),
(err, data) => {
if (err) {
console.error(err);
} else {
console.log(data.message_uuid);
}
}
);
});
};
Finalisieren Sie die Geschäftslogik
Der folgende Code ist für den Aufruf der zuvor erstellten Hilfsfunktionen verantwortlich. Wenn der Termin verfügbar ist, wird er in die Datenbank aufgenommen und die SMS an den Nutzer zurückgeschickt. Andernfalls wird er aufgefordert, einen anderen Termin zu wählen.
let available = await checkIfAvailable(slot);
if (available) {
let code = addToDatabase();
await sendSMStoUser(code);
response.send(`This slot is available, booking it for you now: ${slot}`);
} else {
// Sends user error
response.send(
`Sorry, you'll need to choose a different slot.${slot} is already busy.`
);
} Den Termin absagen/cancelAppointment
Erstellen wir den /cancelAppointment Endpunkt, der die POST-Anfragen zur Stornierung eines Termins aus der Datenbank bearbeitet, indem er einen vom Benutzer bereitgestellten Code verwendet, den er bei der Planung seines Termins erhalten hat.
app.post('/cancelAppointment', async (request, response) => {
let code = request.body.code;
// Removes slot from the database
removeSlotFromDB = (code) => {
ref.child(code).remove();
};
removeSlotFromDB(code);
response.send(`This slot has been removed.`);
});
Den Hafen anhören
Schließlich wird die Anwendung auf dem angegebenen Port lauschen; wenn sie lokal ausgeführt wird, ist sie erreichbar unter https://localhost:${port}. Unter dieser URL können Sie mit der Benutzeroberfläche dieser Demoanwendung interagieren und die hinzugefügten/entfernten Slots auf der Firebase-Konsolen-Webseite überprüfen.
app.listen(port, () => {
console.log(`I run on port ${port}`);
});
Testen Sie es aus
In Ihrer
package.jsonDatei fügen Sie das Startskript"start": "node script/server.js"direkt unter"test": "echo \"Error: no test specified\" && exit 1",. Es sollte wie folgt aussehen:
Installieren Sie alle Abhängigkeiten
npm installFühren Sie den NPM-Befehl aus, um das Projekt auszuführen
npm run startNavigieren Sie zu
http://localhost:3000Hinzufügen und Entfernen von Terminen und Anzeige, wie sie in der Firebase Realtime Database hinzugefügt und entfernt werden
Example adding a slot and it being shown on the Firebase Realtime database
Schlussfolgerung und nächste Schritte
Heute haben Sie gesehen, wie man eine Demo-Webanwendung für einen Terminplaner erstellt. Jetzt können Sie weitermachen und ein ausgefalleneres Styling und andere Funktionen hinzufügen. Mit dem, was Sie hier gelernt haben, können Sie viele Terminplaner erstellen, sei es für ein Fitnessstudio oder für einen Impftermin - lassen Sie Ihrer Kreativität freien Lauf!
Erreichen Sie uns auf Twitter und treten Sie unserer Gemeinschaft auf Slack bei.