ランディングページ製品一覧

概要説明

ランディングページ向けに公開用の製品一覧を提供するエンドポイントです。認証不要で高速かつ信頼性を重視し、公開表示に適した安全な最小限のフィールドのみを返却します。主な用途は、特集・新着・人気製品の表示などです。

本エンドポイントは基本的なフィルタリングとページネーションをサポートし、ランディングページのグリッド表示を高速かつ安定的に描画できます。

Swagger リンク

API: Landing Products API

アクティビティ図

---
config:
  theme: base
  layout: dagre
  flowchart:
    curve: linear
    htmlLabels: true
  themeVariables:
    edgeLabelBackground: "transparent"
---
flowchart TB
    Visitor[Visitor]
    Controller[LandingPageController]
    Service(ProductService)
    Cache[(Cache)]
    Database[(Database)]

    Visitor --- Step1[
      <div style='text-align: center'>
        <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; border-radius: 50%; font-weight: bold'>1</span>
        <p style='margin-top: 8px'>GET /api/v1/landing-page/products</p>
      </div>
    ]
    Step1 --> Controller

    Controller --- Step2[
      <div style='text-align: center'>
        <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
        <p style='margin-top: 8px'>クエリの検証</p>
      </div>
    ]
    Step2 --> Service

    Service --- Step3[
      <div style='text-align: center'>
        <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
        <p style='margin-top: 8px'>キャッシュ取得</p>
      </div>
    ]
    Step3 --> Cache

    Cache --- Step4[
      <div style='text-align: center'>
        <span style='display: inline-block; background-color: #99cc66 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4</span>
        <p style='margin-top: 8px'>ミス時にDB問い合わせ</p>
      </div>
    ]
    Step4 --> Database
    Database --> Service
    Service --> Controller

    Controller --- Step5[
      <div style='text-align: center'>
        <span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5</span>
        <p style='margin-top: 8px'>JSON レスポンス</p>
      </div>
    ]
    Step5 --> Visitor

ケース文書

ケース1: 成功(結果あり)

シーケンス図

sequenceDiagram
    participant Visitor
    participant API as LandingPageController
    participant Service as ProductService
    participant Cache
    participant DB as Database

    Note over Visitor,API: Step 1: GET /api/v1/landing-page/products
    Visitor->>API: GET /api/v1/landing-page/products?page=1&per_page=12&sort_by=created_at&sort_order=desc

    Note over API,Service: Step 2: 検証と取得
    API->>Service: listPublicProducts(params)
    Service->>Cache: get(cacheKey)
    alt Cache hit
        Cache-->>Service: product_list
    else Cache miss
        Service->>DB: SELECT public fields with pagination/sort
        DB-->>Service: rows
        Service->>Cache: put(cacheKey, rows, ttl)
    end

    Note over API,Visitor: Step 3: レスポンス
    API-->>Visitor: 200 OK (products + pagination)

ステップ

ステップ1: リクエスト

  • Method: GET
  • Path: /api/v1/landing-page/products
  • クエリ(すべて任意):
    • page: 整数, 既定 1
    • per_page: 整数, 既定 12
    • q: 検索キーワード(タイトル簡易一致)
    • sort_by: created_at | popularity | price
    • sort_order: asc | desc

ステップ2: 検証・処理

  • page/per_page の数値検証
  • sort_by/sort_order をホワイトリスト検証
  • 可能ならキャッシュ、無ければDB

ステップ3: レスポンス

  • 成功: 200 OK
  • 例:
{
  "success": true,
  "data": {
    "products": [
      {
        "id": "dogparadise:4589602260099",
        "name": "Sample Product",
        "image_url": "https://cdn.example.com/p/4589602260099.jpg",
        "price": 1299,
        "currency": "JPY",
        "rating": 4.6,
        "review_count": 152
      }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 12,
      "total": 145,
      "last_page": 13
    }
  }
}

ケース2: 成功(空結果)

レスポンス例

{
  "success": true,
  "data": { "products": [], "pagination": { "current_page": 1, "per_page": 12, "total": 0, "last_page": 0 } }
}

ケース3: 不正なパラメータ

  • 例: per_page が大きすぎる、sort_by が非対応
  • レスポンス: 400 Bad Request

レスポンス例

{
  "success": false,
  "error": {
    "code": 400,
    "message": "Invalid sort_by. Allowed: created_at, popularity, price"
  }
}

エラーハンドリング

  • 400 Bad Request: クエリが不正
  • 429 Too Many Requests: 公開エンドポイントのレート制限
  • 500 Internal Server Error: 予期せぬエラー(ログ記録)

追加メモ

  • 公開エンドポイントのため認証不要
  • 公開安全なフィールドのみ返却(内部識別子は含めない)
  • 短いTTLでのキャッシュにより性能を向上
  • 初期表示を速くするため per_page は小さめ推奨