[ #LINEDC ] HonoでLINE Message API用の Webhook APIを作る

この記事では、HonoフレームワークでLINE Message APIのWebhook APIを作成する方法を解説しています。署名検証の実装方法や、メッセージ処理関数の分離、リクエストボディの取り扱いなどのポイントが紹介されています。LINEボットを構築する際の参考になる実践的な内容です。

広告ここから
広告ここまで

目次

    LINE上でChatbotを作るには、LINEが受信したメッセージを転送するためのWebhook APIが必要です。一般的には、POSTリクエストを受け付けるパブリックなAPIを作ることになります。今回はHonoでAPIを提供する際の署名検証処理系をまとめてみました。

    最終コード

    コードがあればよい。という方向けに、全体像です。TypeScriptですので、JavaScriptで実装される方は型情報を取り除いてお使いください。

    import { Hono } from 'hono';
    import { validateSignature, WebhookEvent } from '@line/bot-sdk';
    
    interface LineWebhookRequest {
      destination: string;
      events: WebhookEvent[];
    }
    
    type Env = {
      LINE_CHANNEL_SECRET: string;
    };
    
    const app = new Hono<{ Bindings: Env }>();
    
    // LINE Webhook処理
    app.post('/line', async (c) => {
      try {
        const signature = c.req.header('X-Line-Signature');
        if (!signature) {
          return c.text('Signature required', 401);
        }
    
        // リクエストボディを検証
        const body = await c.req.text();
        const isValid = validateSignature(body, c.env.LINE_CHANNEL_SECRET, signature);
        
        if (!isValid) {
          return c.text('Invalid signature', 401);
        }
    
        // Webhookイベントを処理
        const webhookRequest = JSON.parse(body) as LineWebhookRequest;
        const events = webhookRequest.events;
    
        console.log(`LINEイベント受信: ${events.length}件`);
    
        // イベントごとに処理
        for (const event of events) {
          // @TODO メッセージごとの処理を書く
        }
    
        return c.text('OK');
      } catch (error) {
        console.error('LINE Webhookエラー:', error);
        return c.text('Internal Server Error', 500);
      }
    });

    Webhookを実装する際のポイント

    検証系やメッセージ処理系を作るにあたって、意識しておくと良いかなと思った部分を2つ紹介します。

    ポイント1: メッセージ処理関数は、別で用意する

    LINEのWebhookは、1通ごとにイベントが届くわけではない様子です。というのも、Webhookで送信されるデータを見ると、イベントデータが配列型式になっています。そのため、実際の処理系統は、下のコードのようにループの中で実行することになります。

        for (const event of events) {
          // @TODO メッセージごとの処理を書く
        }

    HonoでAPIを登録する部分( app.post() )には、署名検証系のみ実装しておきましょう。これによってリクエストの検証とメッセージ処理の責務が分担できますので、コードの見通しもよくなります。

    ポイント2: リクエストBodyは一旦テキストにする

    JSONでデータが飛んでくるため、このタイプのAPIを作る時はawait c.req.json()でリクエスト内容を取得したくなります。ですがStripeと同様に、LINEでもWebhookの署名検証処理を動かすステップではテキストデータが必要となります。そのためリクエスト内容は、await c.req.text()で取得するようにしましょう。

        // リクエストボディを検証
        const body = await c.req.text();
        const isValid = validateSignature(body, c.env.LINE_CHANNEL_SECRET, signature);
        if (!isValid) {
          return c.text('Invalid signature', 401);
        }

    検証が終わった後は、JSON.parseでテキストからオブジェクトに変換してやります。

        const webhookRequest = JSON.parse(body) as LineWebhookRequest;
        const events = webhookRequest.events;

    二度手間に見えますが、セキュリティ対策としても重要ですので、意識しておくと良さそうです。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark