Lighthouse CIをGitHub Actionsで動かして、Laravelに自動保存してみた2

2025.09.26 09:00
2025.09.28 20:44
Lighthouse CIをGitHub Actionsで動かして、Laravelに自動保存してみた2

前回は GitHub Actions から Lighthouse CI を実行し、Pythonで集計したスコアを Laravel API に POST するところまでを書きました。
今回はその続きで、「Laravel側で受け取って保存する」部分をメモしておきます。
シンプルに FormRequest → UseCase → Eloquent に流す構成にしたので、最小限の実装例として紹介します。

1. Laravel側の受け口

まずは API のルートを用意します。
/api/lighthouse に POST できるようにして、ヘッダには X-Job-Token を付けて認証する仕組みにしました。

<?php

Route::middleware('job.token')->group(function () {
    Route::post('/lighthouse', LighthouseStoreController::class)->name('lighthouse.store');
});

2. バリデーション(FormRequest)

POSTされる内容は「site_id / month / preset / url / scores…」とシンプルなので、
FormRequest にルールをまとめました。

class LighthouseStoreRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'site_id'        => ['required','integer'],
            'month'          => ['required','date'],
            'preset'         => ['required','string','in:mobile,desktop'],
            'url'            => ['required','url'],
            'url_hash'       => ['required','string','size:64'],
            'performance'    => ['required','numeric','between:0,1'],
            'accessibility'  => ['required','numeric','between:0,1'],
            'seo'            => ['required','numeric','between:0,1'],
            'best_practices' => ['required','numeric','between:0,1'],
            'raw_json'       => ['nullable','array'],
        ];
    }
}

3. 保存処理(Controller → UseCase)

コントローラでは Request を受けて、UseCaseに丸投げする形にしました。
保存は updateOrCreate にして、同じ月・同じURLは上書きするようにしています。
DB保存処理は割愛します。

final class LighthouseStoreController extends Controller
{
    public function __invoke(
        LighthouseStoreRequest $request,
        LighthouseStoreUseCase $useCase
    ): JsonResponse {
        $item = $useCase($request->validated());

        return response()->json([
            'message' => 'Lighthouse report stored successfully',
            'data'    => $item,
        ], 201);
    }
}

DBはこんな感じ。
site_id + month + preset + url_hash をユニークキーにしています。

Schema::create('lighthouse_reports', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('site_id');
    $table->date('month');
    $table->string('preset', 16);
    $table->string('url', 2048);
    $table->string('url_hash', 64);
    $table->float('performance');
    $table->float('accessibility');
    $table->float('seo');
    $table->float('best_practices');
    $table->json('raw_json')->nullable();
    $table->timestamps();

    $table->unique(['site_id','month','preset','url_hash']);
});

コントローラでは Request を受けて、UseCaseに丸投げする形にしました。
保存は updateOrCreate にして、同じ月・同じURLは上書きするようにしています。
DB保存処理は割愛します。

5. X-Job-Tokenを設定する

外部(GitHub Actions)から直接APIを叩くので、そのまま公開すると誰でもPOSTできてしまいます。
そこで Laravel 側に 専用トークン認証 を入れておきます。
ヘッダに X-Job-Token を付けて送信し、Laravelで .env に置いた値と突き合わせてチェックするだけのシンプルな仕組みです。

<?php declare(strict_types=1);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

final class VerifyJobToken
{
    public function handle(Request $request, Closure $next): Response
    {
        $expected = (string) config('jobs.token', '');
        $given    = (string) $request->header('X-Job-Token', '');

        if ($expected === '' || !hash_equals($expected, $given)) {
            return response()->json(['message' => 'Unauthorized'], 401);
        }

        return $next($request);
    }
}

上のミドルウェアを登録します。

上部割愛〜

    // インストールしたMiddlewareを指定
    ->withMiddleware(function (Middleware $middleware) {

        // 明示的に指定した時に反映
        $middleware->alias([
            'job.token' => VerifyJobToken::class,
        ]);

以降割愛〜

設定ファイルにキーを置きます。

return [
    // ...
    'job_token' => env('JOBS_TOKEN'),
];

.envにも追加しておきます。

JOBS_TOKEN=your-super-secret-token

これでトークンを持ったアクセスのみをAPIで受けられるようになりました!

5. まとめ

ここまでで「Lighthouse CI → GitHub Actions → Python → Laravel API → DB保存」という流れがつながりました。
まだ最低限の実装ですが、履歴を蓄積できるようになったので、後は一覧で見られる画面やグラフ化を足していけば、定点観測ダッシュボードとして使えるようになります。

今回は以上です!