3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Deno] FreshでLINE Messaging API SDKを使ってみる

Last updated at Posted at 2024-02-21

はじめに

前回のおわりにDenoのフレームワークでLINE Messaging API SDKを使ってみようと書いていたので、Freshでやってみようと思います。

FreshはDenoのフルスタックWeb FrameworkでSSRを基本としてIslands ArchitectureなどモダンなアーキテクチャをサポートしているユニークなFrameworkです。個人的にはなんとなくDenoでのNext.js的な立ち位置を目指しているのかなと思っています。昨年安定版の1.0がリリースされました。

基本的にはSSRなWebアプリを開発できるFrameworkですがカスタムRouteを作成することもできるのでこれでLINE Bot Serverを開発することもできそうです。今回はこのアプローチでやってみます。

やってみる

完成形はこちらです。

プロジェクトを作成する

Create a projectを参考に新規プロジェクトを作成します

$ deno run -A -r https://fresh.deno.dev

 🍋 Fresh: The next-gen web framework. 

Project Name: fresh-linebot
Let's set up your new Fresh project.

Do you want to use a styling library? [y/N] 
Do you use VS Code? [y/N] Y
The manifest has been generated for 5 routes and 1 islands.

Project initialized!

Enter your project directory using cd fresh-linebot.
Run deno task start to start the project. CTRL-C to stop.

Stuck? Join our Discord https://discord.gg/deno 

Happy hacking! 🦕

$ cd fresh-linebot
$ ls
README.md	deno.json	fresh.config.ts	islands		routes
components	dev.ts

VSCodeを設定する

前回記事のVSCodeの設定を追記しておきます。

リクエストハンドラをカスタマイズする

Freshではroutes以下にファイルを作成すれば自動的にルーターが設定されるようになっています。
デフォルトでは./routes/api/joke.tsというサンプルコードが記載されています。/api/jokeにアクセスするとランダムにジョークをレスポンスしてくれるようです。

スクリーンショット 2024-02-19 17.29.41.png

 ためしにこのままWeb Serverを起動して

deno task start

APIを呼ぶとジョークが返ってきました

$ curl http://localhost:8000/api/joke
An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.% 

このhandlerにLINE Messaging API SDKを組み込んでカスタムしていったらよさげですが、このままだとすべてのRequest Methodを受け付けることになるので、WebhooksのPOSTメソッドのみ受け付けるようにしてみます。

/routes/api/joke.ts
import type { Handlers, FreshContext } from "$fresh/server.ts";

// Jokes courtesy of https://punsandoneliners.com/randomness/programmer-jokes/
const JOKES = [
  "Why do Java developers often wear glasses? They can't C#.",
  "A SQL query walks into a bar, goes up to two tables and says “can I join you?”",
  "Wasn't hard to crack Forrest Gump's password. 1forrest1.",
  "I love pressing the F5 key. It's refreshing.",
  "Called IT support and a chap from Australia came to fix my network connection.  I asked “Do you come from a LAN down under?”",
  "There are 10 types of people in the world. Those who understand binary and those who don't.",
  "Why are assembly programmers often wet? They work below C level.",
  "My favourite computer based band is the Black IPs.",
  "What programme do you use to predict the music tastes of former US presidential candidates? An Al Gore Rhythm.",
  "An SEO expert walked into a bar, pub, inn, tavern, hostelry, public house.",
];

export const handler: Handlers =  {
  async POST(_req: Request, _ctx: FreshContext): Promise<Response> {
    console.log(await _req.json());
    const randomIndex = Math.floor(Math.random() * JOKES.length);
    const body = JOKES[randomIndex];
    return new Response(body);
  }
};
$ curl http://localhost:8000/api/joke
$ curl -X POST -H "Content-Type: application/json" -d '{"hello":"world"}' localhost:8000/api/joke
Wasn't hard to crack Forrest Gump's password. 1forrest1.% 

1度目のGETリクエストでは何も返ってきませんが、2度目のPOSTリクエストでジョークが返ってきています。

Watcher File change detected! Restarting!

 🍋 Fresh ready 
    Local: http://localhost:8000/

{ hello: "world" }

Web Serverを起動しているコンソールではconsole.log(await _req.json());の結果としてリクエストボディが出力されています。

前回のシンプルなBot Serverを参考に/routes/api/messaging.tsを作成します。

/routes/api/messaging.ts
import type { Handlers, FreshContext } from "$fresh/server.ts";
import { messagingApi, MessageEvent } from "npm:@line/bot-sdk@8.4.0";
import type { ClientConfig } from "npm:@line/bot-sdk@8.4.0";

const config: ClientConfig = {
    channelAccessToken: "YOUR_CHANNEL_ACCESS_TOKEN",
    channelSecret: "YOUR_CHANNEL_SECRET",
};
const client = new messagingApi.MessagingApiClient(config);

export const handler: Handlers =  {
  async POST(_req: Request, _ctx: FreshContext): Promise<Response> {
    const body = await _req.json() 
    const event: MessageEvent = body.events[0]
    await client.replyMessage({
      replyToken: event.replyToken,
      messages: [
        {
          type: "text",
          text: "Hello, I'm Fresh.",
        },
      ],
    });
    return new Response(null, { status: 204 });
  }
};

YOUR_CHANNEL_ACCESS_TOKEN, YOUR_CHANNEL_SECRETはLINEチャンネルのアクセストークンとチャンネルシークレットに読み替えてください。

TLS Serverにするため fresh.config.ts を以下のように更新します

fresh.config.ts
import { defineConfig } from "$fresh/server.ts";

const keyPath = "/[YOUR_KEY_PATH]/privkey.pem";
const certPath = "/[YOUR_CERT_PATH]/fullchain.pem";
const key = await Deno.readTextFile(keyPath);
const cert = await Deno.readTextFile(certPath);

export default defineConfig({
  key,
  cert,
});

/[YOUR_KEY_PATH]/privkey.pem, /[YOUR_CERT_PATH]/fullchain.pemは各SSL証明書ファイルへのパスに読み替えてください。

これだけで完了です。

実行してみる

LINE BotサーバーをNestJSで開発する その1と同様にEC2を立ち上げてDenoをインストールし、Let's Encriptの証明書を取得した後、上記のパス設定等を更新して実行します。

deno task start

LINEアプリからBotに対してメッセージを送信するとHello, I'm Fresh.と返ってきます。

Screenshot_20240221-133018.png

おわりに

DenoのフルスタックWeb FrameworkであるFreshを使ってLINE Bot Serverを作ってみました。Freshはルーティングの自動生成など開発者がアプリケーションロジックに集中できるような機能が揃っていて高速にWebアプリケーションを開発できます。

個人的にはDenoのおかげでTypeScriptのトランスパイル環境を準備する手間や開発中にビルドのオーバーヘッドがないのは非常に楽だなと感じています。前回と今回の検証でLINE Bot Server開発もDenoに移行していいかもしないなと感じました。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?