コンテンツにスキップ

API層の命名規則

概要

将来のAPI化を見据え、API層の命名規則と実装方針を定める。現在はLivewire + Alpine.jsでフロントエンドを実装しているが、将来的にNextJS + React(Headless)との並立を想定し、API層の設計方針を明確化する。

基本方針

  • Laravel標準の JsonResource を継承したクラスを使用
  • Filament Resourceとの名前衝突を避けるため、サフィックス方式を採用
  • サービス層の分離を徹底し、将来のAPI化コストを最小化

API Resourceの命名規則

命名規則

  • 形式: {Model}ApiResource
  • :
  • ProductApiResource
  • OrderApiResource
  • CategoryApiResource
  • CustomerApiResource

配置場所

app/Http/Resources/
├── ProductApiResource.php
├── OrderApiResource.php
├── CategoryApiResource.php
└── ...

実装例

<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ProductApiResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'slug' => $this->slug,
            'price' => $this->price,
            'description' => $this->description,
            'image' => $this->image,
            'categories' => CategoryApiResource::collection($this->whenLoaded('categories')),
            'brand' => new BrandApiResource($this->whenLoaded('brand')),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}

Filament Resourceとの区別

命名規則の比較

種別 命名規則 配置場所 継承クラス 用途
Filament Resource {Model}Resource app/Admin/Resources/{Model}Resource.php Filament\Resources\Resource 管理画面のUI定義(フォーム、テーブル)
API Resource {Model}ApiResource app/Http/Resources/{Model}ApiResource.php Illuminate\Http\Resources\Json\JsonResource APIレスポンスのJSON形式定義

重要な注意事項

  • API Resource(JsonResource)とFilament Resource(Filament\Resources\Resource)は完全に別物
  • 互いに影響しない(現在の管理画面への影響は一切ない)
  • 名前空間が異なるため、同じディレクトリに配置しても問題ない

将来の拡張(API ファサード別の分離)

将来的にAPI ファサード(Public/Partner/Admin)を分離する場合は、以下の構成も検討可能:

app/Http/Resources/
├── Public/
│   ├── ProductApiResource.php      // 公開API用
│   └── OrderApiResource.php
├── Partner/
│   ├── ProductApiResource.php     // パートナーAPI用
│   └── OrderApiResource.php
└── Admin/
    ├── ProductApiResource.php      // 管理API用
    └── OrderApiResource.php

この場合、各ファサードで異なるレスポンス形式を定義できる。

実装方針

Phase 1: 現在(Livewire + Alpine.js)

  • API Resourceは未実装
  • サービス層を分離して実装することで、将来のAPI化を容易にする
  • : CartService, ProductCatalogService など
// サービス層の分離例
app/Services/CartService.php
app/Services/Catalog/ProductCatalogService.php

// Livewireコンポーネントは薄く保つ
class CartPage extends Component
{
    public function addToCart(int $productId): void
    {
        app(CartService::class)->addToCart($productId);
        $this->dispatch('cart-updated');
    }
}

Phase 2: 将来(API化)

  • 既存のサービス層を活用してAPI ResourceとAPI Controllerを作成
  • Livewire版とAPI版を共存可能に設計
// API Controller例
app/Http/Controllers/Api/ProductApiController.php
class ProductApiController extends Controller
{
    public function index(Request $request)
    {
        $products = app(ProductCatalogService::class)->getActiveProducts();
        return ProductApiResource::collection($products);
    }
}

サービス層の分離原則

将来のAPI化を見据え、以下の原則を守る:

✅ 推奨:サービス層にロジックを集約

// ✅ 良い例:サービス層にロジックを集約
class CartService
{
    public function addToCart(int $productId, int $quantity = 1): void
    {
        // ビジネスロジック
    }
}

// Livewireコンポーネントは薄く保つ
class CartPage extends Component
{
    public function addToCart(int $productId): void
    {
        app(CartService::class)->addToCart($productId);
    }
}

❌ 非推奨:Livewireコンポーネントに直接ロジックを書く

// ❌ 避けるべき:Livewireコンポーネントに直接ロジックを書く
class CartPage extends Component
{
    public function addToCart(int $productId): void
    {
        // ロジックを直接書かない
        $cartItems = session()->get('cart_items', []);
        // ...
    }
}

認証・認可の統一

Livewire版とAPI版で同じ認証・認可ロジックを使えるように:

// app/Policies/ProductPolicy.php(既存を活用)
class ProductPolicy
{
    public function viewAny(User $user): bool
    {
        // Livewire版とAPI版で共通
    }
}

データアクセス層の抽象化

リポジトリパターンやEloquentのクエリを共通化:

// app/Repositories/ProductRepository.php(将来作成)
class ProductRepository
{
    public function getActiveProducts(): Collection
    {
        return Product::where('is_active', true)
            ->with(['categories', 'brand'])
            ->get();
    }
}

まとめ

  • API Resourceの命名: {Model}ApiResource(サフィックス方式)
  • 配置場所: app/Http/Resources/{Model}ApiResource.php
  • 現在の実装: サービス層の分離を徹底
  • 将来の実装: 既存のサービス層を活用してAPI化
  • 管理画面への影響: 一切なし(Filament Resourceとは完全に独立)

この方針により、現在のLivewire + Alpine.js実装と、将来のNextJS + React(Headless)の並立をスムーズに行える。