https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-an-appointment-scheduler-using-node-firebase-and-vonage/appointment-scheduler.png

Node、Firebase、Vonageを使って予約スケジューラーを構築する

最終更新日 December 16, 2021

所要時間:5 分

はじめに

このチュートリアルでは、Node.js、Express、Firebase、そして Vonage Messages APIを使用します。.このプロジェクトの このプロジェクトの GitHub リポジトリもあります。.

Firebaseのセットアップ

はじめに Firebaseコンソール.

  • をクリックする。 add a new project

  • プロジェクトに意味のある名前をつける。 vonage appointment scheduler

  • プロジェクトの一意な識別子ID(リアルタイムデータベースURL、Firebaseホスティングサブドメインなどで使用されます。プロジェクト作成後に変更することはできません。)

  • ボタンをクリックして続ける

Console view with a text field to enter project and name and edit the project idConsole view with a text field to enter project and name and edit the project id

  • アナリティクスを有効にするかどうかを選択します。このチュートリアルでは使用しません。

  • ボタンをクリックしてプロジェクトを作成する

  • プロジェクトが作成されるのを待つ

Project being createdProject being created

  • プロジェクトの準備ができたら、続けるをクリックします。プロジェクトのコンソールビューが表示されます。

  • 歯車のアイコンをクリックして課金タイプを設定し、次に「使用状況と課金」をクリックし、「詳細と設定」タブをクリックしてBlazeを使用するプランを変更します。この従量課金プランは、サードパーティAPIを使用する場合に必要です。

Firebase Tools CLIをインストールする

ターミナルから、FirebaseツールをNPMでインストールする: npm install -g firebase-tools.次に、firebase login と入力する。ブラウザのウィンドウが開き、自動的に認証されるか(すでにログインしている場合)、認証情報の入力を求められます。これでFirebase CLIのインストールは完了です。

リアルタイム・データベースの作成とセットアップ

次に、アポイントメントスロットの情報を保持するNoSQLデータベースインスタンスを作成します。私たちのアプリにはユーザーが予約を入れたりキャンセルしたりできるビューがあります。ビューを操作する人がアポイントメントの日時を選択すると、そのスロットはFirebase RealTimeデータベースから追加または削除されます。

  • Firebaseコンソールのメニューから、Buildの下にある "Realtime Database "をクリックします。

Button to create the databaseButton to create the database

データベースJSONファイルのインポート

すでに割り当てられたスロットがあり、これからスロットを追加したり削除したりすることができるデータベースをインポートしてみましょう。以下のスニペットにあるJSONを含む myAppointments.jsonというファイルを作成し、コンソールからこのファイルをインポートします。

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 DatabaseImport Database

データベースのルールを追加する

Firebase Realtime Database Rules は、データベースにアクセスできる人、インデックスの作成方法、データの構造化を決定します。

  • FirebaseコンソールのRealtimeデータベースビューに "Rules "という項目があるので、そのタブをクリックします。ルールの編集画面が表示されます。

  • 以下のコード・スニペットのルールをコピーしてコンソールに貼り付け、コレクションを myAppointmentsコレクションが dateフィールドによってインデックスされるコレクションを設定するためです。

  • をクリックする。 Publish

{
  "rules": {
    ".read": "now < 1643842800000",  // 2022-2-3
    ".write": "now < 1643842800000",  // 2022-2-3
    "myAppointments": {
      ".indexOn": ["date"]
    }
  }
}

Edit Firebase Database RulesEdit Firebase Database Rules

プロジェクト構造の作成

このチュートリアルが終わるころには、あなたのプロジェクトの構造はおおよそこのようになっているでしょう。次のステップでは、コンテンツ、外観、機能性を構築し、使用するサービスを処理するファイルを作成します。

Project Structure also displayed as a code block below for accessibilityProject Structure

appointment-scheduler | public | |- styles | | | L styles.css | |- favicon.ico | L index.html |- script | |- server.js |- .env |- .firebaserc |- README.md |- firebase.json |- package-lock.json |- package.json |- serviceAccountKey.json

セットアップ

  • プロジェクト・フォルダーを作成し cdを作成する: mkdir appointment-scheduler && cd appointment-scheduler

  • NPMを初期化する: npm init.このコマンドはプロジェクトに関する情報を追加するよう促します。

  • 依存関係をインストールします: npm install @vonage/server-sdk dotenv uuid express firebase-admin firebase-functions

  • タイプ firebase init.ダッシュボードですでにプロジェクトを作成しているので、「Type」を選択します。 Use an existing projectを選択すると、必要なプロジェクトを選択するよう促されます。私のプロジェクトID vonage-appointment-schedulerを選択してください。また Realtime Database機能

? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance === Project Setup First, let's associate this project directory with a Firebase project. You can create multiple project aliases by running firebase use --add, but for now, we'll just set up a default project. ? Please select an option: Use an existing project ? Select a default Firebase project for this directory: vonage-appointment-scheduler (vonage appointment scheduler) i Using project vonage-appointment-scheduler (vonage appointment scheduler)

HTMLコンテンツを作成する

HTMLのinput要素には、日付や時刻を選択するための多くのタイプオプションがあることをご存知だろうか。例えば date, datetime-local, time.このチュートリアルでは <input type="datetime-local">.この方法は、日付-時間ライブラリを使用する場合と比べて、いくつかの矛盾が発生する可能性があるため、おそらく堅牢ではありませんが、このチュートリアルの目的には機能します。例えば、18:00は予約可能ですが、18:01は予約できません。

  • を作成します。 public/index.htmlを作成し、以下のコードスニペットを追加することで、新しいアポイントメントを選択したり、キャンセルしたりすることができます。

  <!-- 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スタイリングの追加

このデモ・ウェブ・アプリでは、コンテンツをページの中央に配置し、入力が無効な場合は赤い✖を、有効な場合は✓を表示するようにスタイルを追加します。

  • を作成する。 public/styles.cssファイル

  • 以下のCSSコードを貼り付けます。

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;
}

環境変数ファイルの作成

  • を作成し .envを作成し、以下の情報を入力する。

FIREBASE_DATABASE_URL= VONAGE_API_KEY= VONAGE_API_SECRET= VONAGE_FROM_NUMBER= VONAGE_TO_NUMBER=
  • FIREBASE_DATABASE_URLはFirebaseのコンソール

  • その VONAGE_API_KEYVONAGE_API_SECRETダッシュボード

  • には VONAGE_FROM_NUMBERには、メッセージの送信者として表示される番号、名前、またはブランドが含まれます。

  • VONAGE_TO_NUMBERはSMSメッセージを受信する番号です。

JavaScriptファイルの作成server.js

を作成する。 server.jsを作成し、UIから投稿されたリクエストの処理方法をExpressに伝えます。どのように構築するか、順を追って説明しよう。 サーバーファイル一式はこちら.

ウェブ・アプリはexpressを使い、以前に作成した静的ファイルを publicフォルダから作成した静的ファイルを読み込みます。

  • 依存関係とインポートファイルを追加するには、以下のコード・スニペットを 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 }));

サービスアカウントの追加

Firebase サービスアカウントは、Firebase の様々な機能を認証するために使用できます。今回のプロジェクトでは、Firebase Admin SDK を使用して Database URL にアクセスします。

  • Firebase Consoleから歯車をクリックし、Service Accountタブを選択します。

  • ボタンをクリックして generate key

  • 生成されたファイルをプロジェクトのルートに追加し、名前を次のように変更する。 serviceAccountKey.json

  • このチュートリアルの次のステップにあるように、Admin SDKの設定スニペットをコピーしてプロジェクトに貼り付け、Firebaseを初期化します。Firebaseを初期化するために ${process.env.FIREBASE_DATABASE_URLファイルから URL を読み取るために .envファイルから URL を読み込むために使用していますが、これは Firebase Admin SDK 設定にあるのと同じデータベース URL です。

Admin SDK configurationAdmin SDK configuration

Firebaseの初期化

私たちは initializeAppを使用して Firebase アプリのインスタンスを作成し、初期化します。 /myAppointmentsFirebase データベースインスタンスの作成と初期化に使用します。

  • 以下のコード・スニペットを server.jsに追加します。

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');

Vonage API オブジェクトの初期化

Vonage クライアント・クラスのインスタンスを作成し、Vonage API Key と Secret で初期化します。 .envファイルに追加した

  • 以下のコード・スニペットを server.jsに追加します。

const vonage = new Vonage({
  apiKey: process.env.VONAGE_API_KEY,
  apiSecret: process.env.VONAGE_API_SECRET,
});

getDateTime() 関数の作成

HTML入力タイプ datetime-localYYYY-MM-DDThh:mm.そこで、日付と時間を文字で分割する関数を書きます。 T.例えば 2018-06-12T19:30では 2018-06-12となります。 19:30となります。

  • 以下のコード・スニペットを server.jsに追加します。 getDateTime()関数

  const getDateTime = (slot) => {
    return slot.split('T');
  };

を作成する。/appointmentエンドポイント

アポイントメントを作成するための /appointmentエンドポイントを作成しましょう。このエンドポイントはスロットが利用可能かどうかをチェックし、Firebaseデータベースにスロットを追加し、最後にVonage Messages APIを使用してユーザーの電話にSMSで確認を返します。

  • 以下のコード・スニペットを server.jsに追加して /appointmentエンドポイントを作成します。

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) => {};
});

リクエストハンドラ内の機能の多くがまだ実装されていないことにお気づきかもしれない。

スロットの空き状況を確認する

この関数は、スロットがすでにデータベースに存在するかどうかをチェックすることで、スロットが利用可能かどうかを検証します。この関数は ref.orderByChild('date').クエリは一度に1つのキーを指定することができます。パフォーマンスを向上させるために .indexOnでインデックスを定義しています。そして .once('value')を使用して、値のイベントを1回だけリッスンし、その後リッスンを停止します。

  • 以下のコード・スニペットを server.jsに追加します。 checkIfAvailable()関数

  // 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;
  };

スロットをデータベースに追加する

次の関数 addToDatabase()はFirebaseデータベースにスロットとコードを追加します。このコードは予約をキャンセルするために必要です。

  // Adds the slot to the database
  addToDatabase = () => {
    let code = uuidv4();

    ref.child(code).set({
      date: slot,
      userId: code,
    });

    return code;
  };

予約情報をSMSで送信する

最後に、スロットが予約されると、SMSで確認が送信されます。 Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment.関数 sendSMStoUser().

  • 以下のコード・スニペットを server.jsに追加します。 sendSMStoUser()関数

// 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);
        }
      }
    );
  });
};

ビジネス・ロジックを確定する

以下のコードは、先に作成したヘルパー関数を呼び出す役割を担っています。もしその時間帯が空いていれば、ユーザーはその時間帯をデータベースに追加し、SMSを送り返します。そうでない場合は、別の時間帯を選択するように要求されます。

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.`
	);
}

予約のキャンセル/cancelAppointment

を作成しましょう。 /cancelAppointmentエンドポイントを作成しましょう。ユーザーがアポイントメントをスケジューリングしたときに受け取ったコードを使用して、データベースからアポイントメントをキャンセルするためのPOSTリクエストを処理します。

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.`);
});

港を聴く

最後に、アプリは指定されたポートをリッスンする。 https://localhost:${port}.このURLで、このデモアプリケーションのUIを操作し、FirebaseコンソールのWebページで追加/削除されたスロットを確認することができます。

app.listen(port, () => {
  console.log(`I run on port ${port}`);
});

試してみる

  • あなたの package.jsonファイルに開始スクリプト "start": "node script/server.js"を追加する。 "test": "echo \"Error: no test specified\" && exit 1",.以下のようにする:

"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node script/server.js" },
  • すべての依存関係をインストールする npm install

  • NPMコマンドを実行してプロジェクトを実行する npm run start

  • に移動する。 http://localhost:3000

  • アポイントメントスロットの追加と削除、Firebase Realtime Databaseからの追加と削除の確認

Example adding a slot and it is shown on the Firebase Realtime databaseExample adding a slot and it being shown on the Firebase Realtime database

結論と次のステップ

今日、あなたはアポイントメントスケジューラーデモウェブアプリを構築する方法を見ました。ここで学んだことを活かして、スポーツジムや予防接種など様々なアポイントメントスケジューラーを作成することができます。ここで学んだことを活かして、スポーツジムや予防接種など様々なアポイントメントスケジューラーを作成することができます!

ツイッターそして Slackのコミュニティに参加する.

シェア:

https://a.storyblok.com/f/270183/400x400/3f6b0c045f/amanda-cavallaro.png
Amanda Cavallaroデベロッパー・アドボケイト