LINE Notifyを使わずDifyだけでLINEにメッセージを送信する

LINE Notifyが終わってしまうということでLINE Notifyを使わずにDify単体でLINEにメッセージ送信をしたいと思います。

Difyのバージョンは0.15.3です。

## 完成イメージ

こんなワークフローです。

> ![CleanShot 2025-02-26 at 18.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/987471df-b273-4423-a431-28363e1bb0d4.png)

https://x.com/n0bisuke/status/1894682181903040610

## 準備

- Difyのワークフロー作成ができる環境
- LINE Botのアカウント
    - チャンネルアクセストークン
    - 自身へ送信する際のUserId

これらが必要です。



## 解説

大きく分けて

- 初期設定（開始ノードと環境変数）
- コードノード1
- コードノード2
- HTTPノード

の3つを利用しています。

> ![CleanShot 2025-02-26 at 18.38.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/23c91760-5ebc-4a6e-b261-18ff38ab5157.png)

### 0. 初期設定

- 開始ノード

開始ノードには、ユーザーに送信するメッセージを設定するための文字列変数を設定しておきます。sendMessageという名前にしました。

> ![CleanShot 2025-02-26 at 18.42.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/8a0f5369-0bc2-4235-a846-a3e41a1521a5.png)

- 環境変数

また、誰に送信するのか投稿先のIDを設定する必要がありますが、`to`という名前の環境変数を設定し、認証のLINE Botのチャンネルアクセストークンは`line_channel_access_token`という名前にしておきます。

> ![](https://i.gyazo.com/4a64899f87341e4ad15ceaa991e96aed.png)

投稿先のIDは自身のユーザーIDを設定すると試しやすいです。LINE DevelopsersのBOT管理画面内の`チャネル基本設定`にある`あなたのユーザーID`と書いてあるものが自身のユーザーIDです。

> ![CleanShot 2025-02-26 at 18.46.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/65b39a6d-f5a2-43cf-b3ae-45506531495d.png)
> チャンネルアクセストークンは`チャネル基本設定`の右隣のタブの`Messaging API設定`の中に記載があります。

### 1. コードノード1 - Message Objectの作成

[LINE Messaging APIのPushメッセージ](https://developers.line.biz/ja/reference/messaging-api/#send-push-message)のページなどを見るとMessaging APIに送信するメッセージオブジェクトという形式が分かります。

```json
[
        {
            "type":"text",
            "text":"Hello, world1"
        },
        {
            "type":"text",
            "text":"Hello, world2"
        }
]
```

こんな形式です。

- 入力変数: to（環境変数で指定したto）, sendMessage（開始ノードで設定したsendMessage）

> ![CleanShot 2025-02-26 at 18.40.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/cddd2cfd-ebf3-4f56-b859-cfc5c6d8c3b8.png)

```js
function main({to, sendMessage}) {
    const messageObj = {
        "to": to,
        "messages":[
            {
                "type":"text",
                "text": sendMessage
            }
        ]
    };

    return {result: JSON.stringify(messageObj)};
}
```

※わかる人向け

ちなみにここで`コードノード`を使わずに`HTTPノード`に設定するだけでもよかったのですが、[メッセージオブジェクトの検証](https://developers.line.biz/ja/reference/messaging-api/#validate-message-objects-of-push-message)を応用的にしたいかもなと思ったので手前でメッセージオブジェクトの作成をしています。

### 2. コードノード2 - X-Line-Retry-Keyの生成（スキップしてもOK）

ここでは[リトライ用のリトライキー](https://developers.line.biz/ja/docs/messaging-api/retrying-api-request/)として、UUIDを生成しています。

なくても動くのでスキップしてもOKですが、その場合HTTPノードのヘッダーも削除します。
入力変数は特にないです。

※Claude 3.7に書いてもらいました。

```js
/**
 * 環境に応じて最適なUUID生成方法を使用
 * @returns {string} 生成されたUUID
 */
function generateUUID() {
    // 方法1: crypto.randomUUID()を試す（Node.js 14.17.0以降で使用可能）
    if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
        return crypto.randomUUID();
    }
    
    // 方法2: Node.jsのcrypto moduleを使用
    try {
        const crypto = require('crypto');
        return crypto.randomUUID();
    } catch (e) {
        // crypto moduleが使用できない場合は次の方法を試す
    }
    
    // 方法3: crypto.getRandomValues()を試す
    if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
        const buffer = new Uint8Array(16);
        crypto.getRandomValues(buffer);
        
        // UUID v4標準に準拠するように特定のビットを調整
        buffer[6] = (buffer[6] & 0x0f) | 0x40;  // version 4
        buffer[8] = (buffer[8] & 0x3f) | 0x80;  // variant RFC4122

        // UUIDフォーマットに変換
        let uuid = '';
        for (let i = 0; i < 16; i++) {
            uuid += buffer[i].toString(16).padStart(2, '0');
            if (i === 3 || i === 5 || i === 7 || i === 9) {
                uuid += '-';
            }
        }
        return uuid;
    }
    
    // 方法4: Math.random()を使用（フォールバック）
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        const r = Math.random() * 16 | 0;
        const v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

function main() {
    // 環境に応じて最適なUUID生成方法を選択
    const uuid = generateUUID();
    
    return {
        result: uuid
    }
}
```

> ![CleanShot 2025-02-26 at 18.52.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/0628a3e0-b056-461b-8455-d1f5f96ef0fa.png)

### 3. HTTPノード - メッセージの送信本体

本体です。 ヘッダーの`Authorization`キーに対して値が`Bearer {チャンネルアクセストークン}`という形式にするところが注意ポイントな気がします。Bearerの後はスペースが必要です。

- メソット: POST
- URL: `https://api.line.me/v2/bot/message/push`
- ヘッダー: 
    - `Authorization`: `Bearer {環境変数に入れたチャンネルアクセストークン}`
    - `X-Line-Retry-Key`: `{コードノード2つ目の結果のUUID}`
- ボディ: JSON指定、{コードノード1つ目の結果のメッセージオブジェクト}
  
> ![CleanShot 2025-02-26 at 18.56.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/4209193b-af11-4311-9be6-62bb21428c32.png)


## まとめ

LINE Notifyを使わずにPushメッセージでLINEに送信する仕組みを作りました

たぶん動く（試してない）DSLをおいておきます。

> https://gist.github.com/n0bisuke/50b06c279f5ce74e4162eea9c52f5c2c

これをワークフロー公開してツールとして使えるようにしておけば結構便利な気がしますね。