👃

DenoとHonoを使って鼻毛APIと鼻毛LINE Botを作ったお話

2023/02/27に公開

初めに

先日Denoに入門したのでせっかくだから学んだことを活かしつつ、普段お世話になっているサービスのAPIとBotを作ってみました。

入門記事はこちら。
https://zenn.dev/iwamasa/articles/a14db17f8ce5ea

なぜ鼻毛なのか?

鼻毛API?鼻毛LINE Bot?なんのこと?こいつ何言ってんだって多分思われると思うのですが、
私は毎月先輩方と一緒に鼻毛脱毛に行くという使命を背負っています。

その脱毛のお店がこちら。
https://www.ekibana.com/

毎月必ず行くため、先輩方とLINEでいつ行くかのやりとりをします。
そのプロセスが以下です。

  1. 今月の鼻毛はいつにしますか?と、メッセージを送る
  2. 土日祝日で希望日を募る
  3. ekibanaのサイトから出店情報を確認する
  4. スケジュール確定

ekibanaは移動型の店舗なので各々のスケジュールから出店情報を確認する必要があります。
そこで、 LINEで出店情報を確認できたら便利なのでは? と思うことは必然。
いざ実行に至りました。

使用技術

ここまではネタでしたが、以降は真面目に技術のお話をしていきます。

今回は以下の技術を使用して作成しました

  • Deno
  • Hono
    • お世話になっているyusukebeさん作のweb framework
  • LINE Messaging API

成果物はこちら。
https://github.com/MasanoriIwakura/hanage-deno-bot

APIの実装

Honoを使用してルーティングを作成します。
こんな感じ。記述量がとても少なくて直感的です!

index.ts
import { serve } from "https://deno.land/std@0.157.0/http/server.ts";
import { Context, Hono } from "https://deno.land/x/hono@v3.0.0/mod.ts";

const app = new Hono();
app.get("/", (c) => c.text("Welcome to Hanage API!!"));

serve(app.fetch);

実行してみます。

deno run --allow-net index.ts

http://localhost:8000 にアクセス

たったこれだけでエンドポイントを作成できました!

今回は以下のエンドポイントを作成してみました。

const v1 = new Hono();
# 駅一覧
v1.get("/stations", (c: Context) => v1Station(c));
# スケジュール一覧
v1.get("/schedules", (c: Context) => v1Schedule(c));
# 年単位のスケジュール
v1.get("/schedules/:year", (c: Context) => v1ScheduleYear(c));
# 月単位のスケジュール
v1.get("/schedules/:year/:month", (c: Context) => v1ScheduleMonth(c));

const app = new Hono();
app.route("/v1", v1);
app.get("/", (c) => c.text("Welcome to Hanage API!!"));
# LINE BotのWebhook用
app.post("/line-bot", (c: Context) => line(c));

各エンドポイントで Context を使用し、リクエストパラメータの受け取りやレスポンスの生成を行います。

パラメータを使用したサンプル
リクエスト: http://localhost:8000/v1/schedules/2023

export default function (c: Context) {
  const year = c.req.param("year");
  const yearSchedules = schedules[year];
  if (yearSchedules === undefined) {
    return c.notFound();
  }

  return c.json(yearSchedules);
}

レスポンスサンプル(長いので抜粋)

{
    "1": [
        {
            "station": {
                "id": "S-09",
                "name": "馬喰横山駅"
            },
            "from": "2023-01-04",
            "to": "2023-01-08"
        },
        {
            "station": {
                "id": "S-04",
                "name": "市ヶ谷駅"
            },
            "from": "2023-01-09",
            "to": "2023-01-15"
        },
        {
            "station": {
                "id": "S-02",
                "name": "新宿三丁目駅"
            },
            "from": "2023-01-16",
            "to": "2023-01-22"
        },
        {
            "station": {
                "id": "S-07",
                "name": "小川町駅"
            },
            "from": "2023-01-23",
            "to": "2023-01-29"
        },
        {
            "station": {
                "id": "S-09",
                "name": "馬喰横山駅"
            },
            "from": "2023-01-30",
            "to": "2023-01-31"
        }
    ]
}

DenoからLINE Messaging APIを実行する方法

Node.jsはSDKがあるのですが、DenoはサポートしていないのでWebhookを使用します。(2023/2現在)
呼び出し方法についてはこちらの記事を参考にさせていただきました。
https://zenn.dev/tmitsuoka0423/articles/26a4a2009e33b1162ca3

返答メッセージを送りたいので以下のエンドポイントを使用しました。
https://developers.line.biz/ja/reference/messaging-api/#send-reply-message

実装サンプル

const postReplyMessage = async (
  message: string,
  replyToken: string,
) => {
  const body = {
    replyToken,
    messages: [
      {
        type: "text",
        text: message,
      },
    ],
  };

  return await fetch("https://api.line.me/v2/bot/message/reply", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${CHANNEL_ACCESS_TOKEN}`,
    },
    body: JSON.stringify(body),
  });
};

CHANNEL_ACCESS_TOKENDeno.env を使用して環境変数から取得しています。

const CHANNEL_ACCESS_TOKEN = Deno.env.get("LINE_CHANNEL_ACCESS_TOKEN") || "";

デプロイ

デプロイ手順はこちらの記事に記載しているので割愛します。
https://zenn.dev/iwamasa/articles/a14db17f8ce5ea#デプロイしてみよう!

LINE Botの設定

まずはLINE Developersコンソールに登録します。
https://developers.line.biz/ja/

登録後、プロバイダーを作成します。

Messaging APIを選択します。

必要事項を入力し、チャンネルを作成します。

チャンネルを作成後、Messaging API設定にてQRコードが表示されるのでこちらをスマホで読み込むことで
作成したBotを友達として登録することができます。

スマホのLINEから確認

同じページでWebhookの設定が行えるので設定します。

先ほどデプロイしたアプリのLINE Bot用のエンドポイントを設定し、Webhookの利用にチェックを入れます。
※今回はWebhookの再送設定は入れませんでした。

先ほど実装で使用したチャンネルトークンもこちらのページで取得できます。(多分一番下)

LINEからBotを呼び出してみる

今回作成したアプリでは 今月の鼻毛 というワードで自動応答するようにしているため、以下のような返答が返ってくるようになりました!

最後に

Denoに入門してから前から気になっていたHonoを使用してちょっとしたAPIを作成し、そこからLINE Botも作成してみました。

Deno Deployを使用することでサクッとこのようなAPIやBotが作成できるのでどんどん活用しようと思います!

それではみなさん良い鼻毛ライフを!

Discussion