【イベントハンドラ型実装】

はじめに

このページでは、REST-API サーバー開発環境におけるイベントハンドラ型の実装方法について解説します。
イベントハンドラ型は、受信したリクエストに対して単一の処理(UNIT)を即時実行する方式で、シンプルな API や軽量な処理に適しています。

イベントハンドラ型のイベント処理クラスはスキャフォールディングで自動生成できます。
▶スキャフォールディング

なお、生成されたイベント処理クラスはメイン処理クラスの $classes['event'] にクラス名を設定することで適用されます
また、ルーティング定義の event キーにはイベント処理クラス内のメソッド名を指定します。

UNIT の基本概念については、以下のページで詳しく解説しています。
▶イベントハンドラについて

イベントハンドラ型の役割

イベントハンドラ型のイベント処理クラスは、REST-API の処理において以下のような役割を持ちます。

  • 単一の処理(UNIT)を即時実行する
  • 軽量な API や単発レスポンスに適している
  • ステートマシン型よりもシンプルで実装コストが低い
  • ルーティングの event キーに対応するメソッドが直接呼び出される

スキャフォールディング(生成方法)

イベントハンドラ型のイベント処理クラスは以下のコマンドで生成できます。
php worker custom:event-handler <カスタム名>
                    

生成されるファイル例:
app/EventClass/<カスタム名>.php
                    

生成されたクラスはメイン処理クラスの $classes['event'] にクラス名を設定することで適用されます
ルーティング定義の event キーには、イベント処理クラス内のメソッド名を指定します。

カスタムコマンドの仕組みについては以下をご覧ください。
▶カスタムコマンド作成機能

生成されるクラスの構造

スキャフォールディングで生成されるイベントハンドラクラスは以下のような構造になります。
<?php

namespace App\EventClass;

use App\CommandUnits\CommandForHandler;

class <カスタム名> extends CommandForHandler
{
    protected function responseJson($p_param)
    {
        $p_param->response()->json(['message' => 'Hello API']);
    }
}
                    

● 特記事項

  • コマンドで指定した カスタム名 がクラス名になる
  • 生成先は app/EventClass 配下
  • CommandForHandler を継承することでイベントハンドラ型として認識される
  • メイン処理クラスの $classes['event'] にクラス名を設定する
  • ルーティングの event キーにはメソッド名を設定する

レスポンス操作の基本


● ステータスコードの設定

$p_param->response()->status(404, 'Not Found');
                    
理由句は省略可能で、指定しない場合は自動で 200 OK になります。

● ヘッダの設定

$p_param->response()->header('X-Sample', 'value');
                    

● 単発レスポンス

$p_param->response()->text('Hello');
                    
$p_param->response()->json(['message' => 'OK']);
                    
$p_param->response()->file('./path/file.txt');
                    
$p_param->response()->download('./path/file.txt');
                    

チャンク転送・SSE の利用について

イベントハンドラ型実装では、以下のように チャンク転送(Chunked Transfer)SSE(Server-Sent Events) を簡単に利用できます。

● チャンク転送の例

$p_param->response()->chunked("1行目のデータです\n");
$p_param->response()->chunked("2行目:少しずつ送信しています...\n");
$p_param->response()->chunked("3行目:もう少しお待ちください...\n");
$p_param->response()->chunked("4行目:最後のデータです\n");
$p_param->response()->end();
                    

● SSE の例

$p_param->response()->event("1回目のデータです", p_id: "sse0");
$p_param->response()->event("2回目:少しずつ送信しています...", p_id: "sse1");
$p_param->response()->event("3回目:まだ続きます...", p_id: "sse2");
$p_param->response()->event("done", p_event: "end");
$p_param->response()->end();
                    

上記のように、イベントハンドラ型でもストリーミングレスポンスを簡潔に記述できますが、イベントハンドラ型は 1 回のメソッド実行内でレスポンスをまとめて処理する方式のため、以下のようなケースが発生する可能性があります。

  • 送信したデータがネットワーク層で部分的に結合されて届く
  • 複数回に分けたつもりのデータが、クライアント側で一度に受信される
  • 確実な分割送信(逐次ステップ実行)が保証されない

そのため、確実に段階的な送信を行いたい場合や、ステップごとに非同期処理・待機処理(setTimeout など)を挟みたい場合は、以下のように ステートマシン型(ステートマシン型) の利用を推奨します。

▶ステートマシン型実装

ステートマシン型では、UNIT ごとにステータスを分けて処理を実行するため、確実な分割送信・逐次処理・非同期遷移が保証されます。
チャンク転送や SSE を厳密に制御したい場合は、ステートマシン型を選択してください。

Range送信の実装例

Range送信では、バイナリデータやファイルデータの全量をそのまま渡すだけで、 フレームワーク側が Range ヘッダの有無を自動判定し、必要な範囲の切り貼りを行ってレスポンスを返します。
デベロッパーは Range 処理を意識する必要がなく、通常のレスポンスと同じ感覚で扱えます。

Range リクエストの標準仕様については、MDN の解説も参考になります。
>> MDN: HTTP Range Requests

● rangeBinary

$p_param->response()->rangeBinary($binary_data);
                    
バイナリデータの全量を渡すだけで、Range 指定があればフレームワークが自動で切り出して返します。

● rangeFile

$p_param->response()->rangeFile('./path/file.txt');
                    
ファイルパスを渡すだけで、Range 指定に応じた部分送信をフレームワークが自動処理します。

おわりに

イベントハンドラ型は、REST-API サーバー開発において軽量な処理・単発レスポンスを実装する際に最適な方式です。
スキャフォールディングを活用することで、イベント処理クラスの作成を効率化できます。

生成可能なクラス一覧については以下をご覧ください。
▶スキャフォールディング