Next.jsを利用してLINE messaging APIを叩いてブロードキャストメッセージを送信する

Next.jsを活用して公式LINEからの予約ツールを作成したい、という考えの続き。
前回の記事

https://qiita.com/kuma_radcof/items/87d2a83acbe671263bc8

# LINE側の準備
## messaging APIの利用
- LINE開発者ツールからプロバイダー作成
- 新規チャンネル作成してMessaging APIの利用を開始
- 公式LINEを開設（この順じゃないとうまくいかなかった）
- コンソール＞該当プロバイダー＞該当チャンネル＞messaging API設定からチャンネルアクセストークンを発行してコピーしとく

# Next.js側の準備
## やるべきことはAPIのためのファイル`route.ts`の準備
Next.jsでAPI機能を実装するにはappディレクトリ直下にapiディレクトリを作る必要があります。
そしてエンドポイントごとにディレクトリを作り、最終的には`route.ts`のファイルを作ればエンドポイントを叩けるようになります。
例えば`users`へのエンドポイントを作りたければ`app/api/users/route.ts`を作ればOK。
クライアント側、あるいはWebhookでのURLは`ドメイン/api/users`となります。

## UIとなる`page.tsx`の準備
今回はLINEを利用したブロードキャストメッセージの送信だったので、Next.js側では`linetest`ディレクトリを作って`page.tsx`をまず作成しました。
```typescript:src/app/linetest/page.tsx
"use client";

export default function lineTop() {
    // ページ遷移させず、ボタンクリックでメッセージ送信させるためのasync関数の定義
    const sendPushMessage = async () => {
        try {
            // apiをfetchメソッドで叩く
            const response = await fetch("../api/line-test/", {
                "method": "POST",
                "headers": {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({ message: 'Hello LINE!' }),
            })

            // fetch結果に対するエラー処理
            if (!response.ok) {
                const errorData = await response.json();
                throw new Error(errorData.error || "送信に失敗")
            }

            alert("LINEでメッセージを送信しました");
        } catch (e: unknown) {
            console.error(e);
            const errorMessage = e instanceof Error ? e.message : "Unknown error occurred";
            alert(`実行エラー：${errorMessage}`);
        }
    }

    return (
        <div>
            <button type="button" onClick={sendPushMessage}>ブロードキャストメッセージ送信</button>
            <p>※現在はトークン情報を更新しているためメッセージは送信されません</p>
        </div>
    )
}
```
このとき、はじめふと疑問に思ったことが、『**どうやってエンドポイントを叩くか**』ということでした。aタグ？と疑問に思ったのでメンター（ChatGPT）に聞きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524273/802bd855-a557-aa33-2269-1c951b54d901.png)
ということで、上記のようにButtonタグでonClinc属性値を用意して完成となりました。

## APIエンドポイントとなる`route.ts`を作成
続いて、エンドポイントとして`api/line-test`とディレクトリを作成します。
```typescript:src/app/api/line-test/route.ts
import "dotenv/config";

// POSTメソッドでブロードキャストメッセージ（全体）の定義
export async function POST(request:Request) {
    const req = await request.json();
    console.log(req);
    try {
        const LINE_ACCESS_TOKEN = process.env.CHANNEL_ACCESS_TOKEN ? process.env.CHANNEL_ACCESS_TOKEN : process.env.NEXT_PUBLIC_CHANNEL_ACCESS_TOKEN;
        const LINE_API_PATH = "https://api.line.me/v2/bot/message/broadcast";

        const requestHeader = {
            "Content-Type": "application/json",
            Authorization: `Bearer ${LINE_ACCESS_TOKEN}`,
        };

        const requestBody = await JSON.stringify({
            messages: [
            // メッセージ1件目
            {
                type: "text",
                text: "サンプルメッセージです",
            },
        ],
    });

        const response = await fetch(LINE_API_PATH, {
            method: "POST",
            headers: requestHeader,
            body: requestBody,
        });

        if (!response.ok) {
            const errorData = await response.json();
            throw new Error(`APIエラー：${errorData}`);
        }

        return new Response(JSON.stringify({success: true,}),{status: 200,});

    } catch (e:unknown) {
        const errorMessage = e instanceof Error ? e.message : "よくわからないエラー"
        return new Response(
            JSON.stringify(
                {
                success: false,
                error: errorMessage,
                }),
            {
                status: 500,
            }
        );
    }
}

```
今後ローカル環境ではなく、Vercelでの公開を想定していたため、トークン情報などの環境変数については条件分岐で取得できるように書いています。
VercelでNext.jsプロジェクトを作成した場合、環境変数にアクセスするには
`NEXT_PUBLIC_`の接頭辞をつける必要があるので注意です。

# サイト公開（Vervel）側の準備
ローカルでもプログラムの実行はできますが、いずれアプリケーションとして公開することを念頭にして試しにデプロイしてみます。
## CLIからのデプロイ
ターミナルからのデプロイをするには`npm install vercel`ののちに、`vercel`コマンドを実行すればOK。
そうすると、どのアカウントに紐づけるのか、既存のプロジェクトか新規に作るのかなど聞いてくれるので都度答えていけば大丈夫です。

## Githubと連携してのデプロイ
ターミナルからの実行ではなく、ブラウザでVercelにアクセスして、Githubと連携させることで、ローカルからGithubへpushするたびにVercel側で再デプロイが実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524273/08de2892-d9d2-ae81-acf5-fa2e1fb96c61.png)
画像右側にある`Connect Git`をクリックしてGithubアカウントと紐づけて、public repositoryを紐づければOK。数クリックで連携できます。

今後毎回vercelコマンド実行するのはめんどいなーと思ったので、`git push`でそのままデプロイできるように接続してみると以下のエラーが。
```
Error: No Next.js version could be detected in your project. Make sure `"next"` is installed in "dependencies" or "devDependencies"
```
Github上のリポジトリについて、ルートディレクトリがあってその中にNext.jsプロジェクトを作っていたことが問題でした。
接続しているのはルートディレクトリなのに、Next.jsプロジェクト見つかりませんと怒られたのでした。

というわけで、Vercelに移動して当該project>setting>generalからRoot directoryをただしいものに変更すればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524273/0657d831-9396-d895-eed7-a41cae7e575e.png)

ここまできたら、上記で作ったButtonタグをクリックすれば公式LINEから全体に向けたメッセージ送信ができるようになりました。