Airtable でデータを記録して前のコメントを返事するシンプルな LINE BOT をつくったメモ

Airtable でデータを記録して前のコメントを返事するシンプルな LINE BOT をつくったメモです。

LINE BOT の基礎

1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest – Qiita

こちらを参考に LINE BOT の基礎 ができている前提で進めます。

2022 年 7 月の情報で進めます。

Airtable の API Key を控えておく

image

Airtable のアカウントページ で API Key をテキストエディタにメモしておきます。これはこの後の Node.js のソースコードで使います。

今回用の Airtable の Base を作成

image

Airtable のダッシュボードで今回用の Base を作成します。

image

今回は名前を LINE BOT Sample としました。

今回用の Airtable の Table を作成

image

Table を一つ作成します。名前は Record とします。

image

フィールドの名前とフィールドタイプは以下のようにします。

  • UserID
    • フィールドタイプ
      • Single line text
  • Message
    • フィールドタイプ
      • Long text
  • CreatedAt
    • フィールドタイプ
      • Created time

これで準備完了です。

今回用の Airtable の Base の ID を取得

今回用の Airtable の Base の ID を取得します。

image

Airtable の API ページ から今回の Base をクリックします。

image

今回の Base の API ページに移動すると、こちらで app ではじまる Base ID が取得できるのでテキストエディタにメモしておきます。

プロジェクトフォルダで Node.js のパッケージ準備

Visual Studio Code で今回作業するプロジェクトフォルダを開きます。

npm init -y

プロジェクトフォルダ直下で npm の初期化をします。

npm i @line/bot-sdk express

LINE BOT 関連のパッケージのインストールをします。

npm i airtable

Airtable のパッケージのインストールをします。

Node.js のプログラム準備

プロジェクトフォルダ直下に app.js のファイルを作成して以下のプログラムをコピーペーストします。

'use strict';

// Airtable /////////////////////////////////

const Airtable = require("airtable");

// 今回使う Base の Base ID
const BASE_ID = 'BASE_ID';

// Airtable の API Key
const AIRTABLE_API_KEY = 'AIRTABLE_API_KEY';

// Airtable 今回使うの Base を取得
const base = new Airtable({apiKey: AIRTABLE_API_KEY}).base(BASE_ID);

// 今回使う Table を取得(テーブル名:Record)
const table = base('Record');

// LINE /////////////////////////////////////

const express = require('express');

const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
  channelSecret: 'channelSecret',
  channelAccessToken: 'channelAccessToken'
};

const app = express();

app.post('/webhook', line.middleware(config), (req, res) => {
  console.log(req.body.events);

  Promise
    .all(req.body.events.map(handleEvent))
    .then((result) => res.json(result));
});

const client = new line.Client(config);

async function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  // Airtable から一つ前の投稿を取得
  let records;
  try {
    records = await base('Record').select({
      view: 'Grid view',
      maxRecords: 1,
      sort:[
        {
          field: "CreatedAt", 
          direction: "desc"
        }
      ],
      fields: ["UserID", "Message","CreatedAt"]
    }).all();
  } catch (e){
    console.log(e);
  }

  let message = '';
  if(records.length == 0){
    // まだ一つ前の投稿がないとき(はじめての投稿)
    message = `今回のメッセージは\n「${event.message.text}」\nです。はじめての投稿です。`;
  } else {
    const previousMessage = records[0].get('Message');
    message = `今回のメッセージは\n「${event.message.text}」\nです。\n一つ前の投稿は\n「${previousMessage}」\nです。`;
  }

  // Airtable に今回のメッセージを記録
  await table.create([{
    "fields": {
      "UserID": event.source.userId,
      "Message": event.message.text
    }
  }]);

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: message
  });

}

app.listen(PORT);
console.log(`Server running at ${PORT}`);

コピーアンドペーストできたら、設定をします。

// 今回使う Base の Base ID
const BASE_ID = 'BASE_ID';

// Airtable の API Key
const AIRTABLE_API_KEY = 'AIRTABLE_API_KEY';

今回使う Base の Base ID と Airtable の API Key を反映します。

const config = {
  channelSecret: 'channelSecret',
  channelAccessToken: 'channelAccessToken'
};

今回使う LINE の channelSecret と channelAccessToken を反映します。

設定できたら LINE BOT を動かしてみます。

動かしてみる

Airtable の Base が空の状態で「やほー」とメッセージしたあと、「こんにちは!」とメッセージします。

image

Base にはこのように情報が貯まります。

image

そして、このようにやりとりされます。「やほー」を送ったときは、はじめての投稿なので今回のメッセージのみで前のメッセージはなし、それ以降は、今回のメッセージと一つ前のメッセージを返答します。

Airtable から一つ前の投稿を取得する処理

一つ前の投稿を取得する、大事な部分はここです。

  // Airtable に今回のメッセージを記録
  await table.create([{
    "fields": {
      "UserID": event.source.userId,
      "Message": event.message.text
    }
  }]);

まず、Airtable にデータが登録されるときに CreatedAt で自動的に作成日時が登録されます。UserID と Message しか登録していないんのですが、CreatedAt で自動的に作成日時が登録されます。

image

そして、データの取得です。

  // Airtable から一つ前の投稿を取得
  let records;
  try {
    records = await base('Record').select({
      view: 'Grid view',
      maxRecords: 1,
      sort:[
        {
          field: "CreatedAt", 
          direction: "desc"
        }
      ],
      fields: ["UserID", "Message","CreatedAt"]
    }).all();
  } catch (e){
    console.log(e);
  }

こちらのコードで sort パラメータで CreatedAt を狙ってソートをかけます。その上で maxRecords 1 によって 1 件だけ取得することで最新のデータ取得を実現しています。