はじめに:モデルをそのまま返すのは危険?
こんにちは、編集長Kです。
APIを作るとき、つい手を抜いていませんか?
DBから取ったデータをそのままJSONで返す。
実はこれ、すごく危険な行為かも。
見せてはいけないパスワード等の情報が漏れる原因になります。
今日は、安全なAPI作りに欠かせないお話をします。
「API Resource(リソース)」クラスの作り方です。
この記事で解説する全体像は以下の通りです。
- なぜResourceクラスが必要なのか?
- 導入することで得られる3つの絶大メリット
- 手順①:Resourceクラスの作成
- 手順②:データの整形(中身の書き方)
- 手順③:コントローラーでの呼び出し方
【前提条件】
- Laravelの開発環境が手元にあること
- データベースからデータを取得した経験があること
なぜ必要?レストランに例えて解説
システムをレストランだと想像してみてください。
データベースは冷蔵庫の中の「生の食材」です。
お客さん(画面側)から「ハンバーグ定食!」と注文が入ります。
このとき、冷蔵庫から出した生のひき肉を直接投げつけますか?
絶対にしませんよね。お腹を壊してしまいますし、お店の秘伝のレシピもバレてしまいます。
ここで必要なのが「キレイに盛り付けるシェフ」です。
このシェフの役割こそが、API Resourceというわけです。
シェフを雇うメリットは大きく3つあります。
【1. セキュリティ向上】見せたくない裏側のメモ(パスワード等)を隠してくれます。
【2. 型の安定】画面側が扱いやすいデータ形式に整えてくれます。
【3. パフォーマンス向上】N+1問題という重たい処理を防いでくれます。
まさに一石三鳥の素晴らしい仕組みなんです。
手順①:Resourceクラスを作成する
それでは、実際にシェフを雇いましょう。
コマンドライン(ターミナル)を開いてください。
まずは、下記を実行してください。
php artisan make:resource UserResourceこれでOKです。
「app/Http/Resources」の中に新しいファイルができましたね。
準備はとても簡単ですね。
手順②:データの整形ルールを書く
次に、シェフに盛り付けのルールを教えます。
作成されたUserResource.phpを開いてください。
続いて、下記のように書き換えます。
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
// 基本情報だけをお皿に乗せる
'id' => $this->id,
'name' => $this->name,
// パスワードなどの機密情報は絶対にここに入れない!
// プロフィールは一緒に注文された時だけ乗せる
'profile' => $this->whenLoaded('profile', function () {
return [
'avatar_url' => $this->profile->avatar_url,
];
}),
];
}
}これで安心です。
【whenLoaded】を使うのがプロの技です。
事前にデータが読み込まれている時だけ出力してくれます。
これで無駄なデータベースへの問い合わせが消え去ります。
手順③:コントローラーで呼び出す
最後に、出来上がった料理をお客さんに出します。
UserControllerなどを開いてください。
続いて、下記のように記述します。
<?php
namespace App\Http\Controllers;
use App\Http\Resources\UserResource;
use App\Models\User;
class UserController extends Controller
{
// 1人のデータを返す場合
public function show($id)
{
$user = User::findOrFail($id);
// 1人の場合は「new」を使う
return new UserResource($user);
}
// 複数のデータを返す場合
public function index()
{
// 関連データも一緒に事前取得(Eager Loading)
$users = User::with('profile')->get();
// 複数の場合は「collection」を使う
return UserResource::collection($users);
}
}バッチリですね、これで完了です。
お客さんには、安全で綺麗なデータだけが届きます。
1人の時は【new】を使い、複数の時は【collection】を使います。
ここだけ注意してくださいね。
現場のリアル:よくあるエラーと解決策
私が現場でよくハマったポイントを共有しておきます。
プロパティが存在しないエラー
「Trying to get property of non-object」などのエラーです。
これはResource内で「$this->」を忘れた時によく出ます。
単なる「id」ではなく「$this->id」と書く必要があります。
コピペした時に忘れがちなので、しっかり確認しましょう。
whenLoadedを使っているのにN+1が起きる
Resource側は正しくても、コントローラー側でミスがあるかも。
データの取得時に「with(‘profile’)」を忘れていませんか?
コントローラーでの「事前注文」が必須というわけです。
まとめ:Resourceクラスで安全なAPIを!
お疲れ様でした。
これであなたもAPI Resourceマスターですね。
生のモデルをそのまま返すのは今日で卒業しましょう。
少しの手間で、何百時間ものバグ探しから解放されます。
Trade Agencyでは、こうした実践的な開発テクニックを発信中です。
ぜひ、あなたのプロジェクトでも今日から取り入れてみてください!

コメント