Denoのnpm importでLINE Messaging API SDKが使えるかやってみる

# はじめに

Denoはv1.25以降から[npmモジュールがimport](https://examples.deno.land/npm)できるようになっています。これで[LINE Messaging API SDK for node.js](https://github.com/line/line-bot-sdk-nodejs)をインポートして利用できるかやってみました。

# やってみる

## VSCodeを設定する

VSCodeを使っている場合、[Deno extension](https://docs.deno.com/runtime/manual/references/vscode_deno/)を有効にしたりnpm importしたモジュールのタイプヒントを表示したりすると便利です。

```.vscode/extensions.json
{
  "recommendations": [
    "denoland.vscode-deno"
  ]
}
```

```.vscode/settings.jsion
{
  "deno.enable": true,
  "deno.enablePaths": ["./"],
  "deno.unstable": true,
  "deno.lint": true,
  "deno.path": "/Users/user/.deno/bin/deno"
}
```

`/Users/user/.deno/bin/deno`は自分のPCのdeno cliのパスに読み替えてください。

```import_map.json
{
  "imports": {
    "npm/": "https://unpkg.com/"
  }
}
```

## Massaging API Client を作成する

ためしに Massaging API Clientを作成するところまで実行してみます。

```main.ts
import { messagingApi } 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)
console.log(client)
```

```shell
deno run -A main.ts

MessagingApiClient {
  httpClient: HTTPClient {
    config: {
      defaultHeaders: { Authorization: "Bearer YOUR CHANNEL ACCESS TOKEN" },
      responseParser: [Function: bound parseHTTPResponse],
      baseURL: "https://api.line.me"
    },
    instance: [Function: wrap] {
      constructor: [Function: wrap],
      request: [Function: wrap],
      getUri: [Function: wrap],
      delete: [Function: wrap],
      get: [Function: wrap],
      head: [Function: wrap],
      options: [Function: wrap],
      post: [Function: wrap],
      postForm: [Function: wrap],
      put: [Function: wrap],
      putForm: [Function: wrap],
      patch: [Function: wrap],
      patchForm: [Function: wrap],
      defaults: {
        transitional: {
          silentJSONParsing: true,
          forcedJSONParsing: true,
          clarifyTimeoutError: false
        },
        adapter: [ "xhr", "http" ],
        transformRequest: [ [Function: transformRequest] ],
        transformResponse: [ [Function: transformResponse] ],
        timeout: 0,
        xsrfCookieName: "XSRF-TOKEN",
        xsrfHeaderName: "X-XSRF-TOKEN",
        maxContentLength: -1,
        maxBodyLength: -1,
        env: { FormData: [Function], Blob: [class Blob] },
        validateStatus: [Function: validateStatus],
        headers: {
          common: [Object],
          delete: {},
          get: {},
          head: {},
          post: {},
          put: {},
          patch: {},
          Authorization: "Bearer YOUR CHANNEL ACCESS TOKEN",
          "User-Agent": "@line/bot-sdk/8.4.0"
        },
        baseURL: "https://api.line.me"
      },
      interceptors: {
        request: InterceptorManager { handlers: [] },
        response: InterceptorManager { handlers: [Array] }
      },
      create: [Function: create]
    }
  }
}
```

なんかやれそうな感じです。

## シンプルなBot Serverを作ってみる

[Deno標準のhttpサーバー](https://docs.deno.com/runtime/tutorials/http_server)でシンプルなBotを作ってみます。

```main.ts
import { messagingApi } from "npm:@line/bot-sdk@8.4.0"
import type { ClientConfig } from "npm:@line/bot-sdk@8.4.0"
import { MessageEvent } 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)

const handler = async (request: Request): Promise<Response> => {
    if (request.method.toUpperCase() === "POST") {
        const body = await request.json() 
        const event: MessageEvent = body.events[0]
        await client.replyMessage({
            replyToken: event.replyToken,
            messages: [
                {
                    type: "text",
                    text: "Hello, I'm Deno.",
                },
            ],
        })
    }
    return new Response(null, { status: 204 })
}

const options = {
    port: 443,
    cert: await Deno.readTextFile("CERT_FILE_PATH"),
    key: await Deno.readTextFile("CERT_KEY_PATH"),
}

Deno.serve(options, handler)
```

上記のコードを前回の[LINE BotサーバーをNestJSで開発する その1](https://qiita.com/bathtimefish/items/e6c151632ad1e9ca71ed)と同じようにEC2インスタンスを立ち上げてDenoをインストールし、Let's Encriptの証明書を取得しました。

上記のコードを実行します。

```shell
 deno run -A main.ts
```

LINE Chatからメッセージを送ると`Hello, I'm Deno.`とだけ返信するBotができました。

<img width="1080" alt="Screenshot_20240210-161247.png (61.0 kB)" src="https://img.esa.io/uploads/production/attachments/3505/2024/02/10/10856/c1e1b021-932a-49fa-b601-987d8fdec251.png">

# おわりに

Denoのnpm importでもLINE Messaging API SDK for node.jsが問題なく動作しそうです。[以前書いた記事](https://qiita.com/bathtimefish/items/8f9d1406f043d6eb02e9)で[deno-linebot](https://deno.land/x/linebot@v1.1.0)を紹介しましたが、特定のWeb server frameworkに依存していてちょっと使い勝手が悪いかなと思っていたのでこちらの方法のほうが自由度が高そうです。個人的には最近Denoを使うことも増えてきたので開発が捗るシーンが出てくるかもしれません。

次回は何かDeno用のweb frameworkを使ってBotを作ってみたいと思います。