Landing Page Products

Overview Description

The Landing Page Products endpoint provides a public list of products for the marketing landing page. It is designed for speed and reliability, does not require authentication, and returns a safe subset of product fields suitable for public display. Typical use cases include showing featured items, newest products, or most popular products.

This endpoint supports basic filtering and pagination so the landing page can render fast and predictable product grids.

Swagger Link

API: Landing Products API

Activity Diagram

---
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'>Validate Query Params</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'>Read From Cache</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'>Cache Miss → Query 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'>Return JSON</p>
      </div>
    ]
    Step5 --> Visitor

Case Documentation

Case 1: Success (Results Found)

Sequence Diagram

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: Validate & Fetch
    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: Response
    API-->>Visitor: 200 OK (products + pagination)

Steps

Step 1: Request

  • Method: GET
  • Path: /api/v1/landing-page/products
  • Query params (all optional):
    • page: integer, default 1
    • per_page: integer, default 12 (reasonable grid size)
    • q: string search keyword (simple title match)
    • sort_by: created_at | popularity | price
    • sort_order: asc | desc

Step 2: Validation & Processing

  • Validate numeric ranges for page/per_page
  • Whitelist sort_by and sort_order
  • Prefer cache; fallback to database

Step 3: Response

  • Success: 200 OK
  • Body example:
{
  "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
    }
  }
}

Case 2: Success (Empty Results)

Sequence Diagram

sequenceDiagram
    participant Visitor
    participant API as LandingPageController

    Visitor->>API: GET /api/v1/landing-page/products?q=zzzz&page=1
    API-->>Visitor: 200 OK ({ products: [], pagination })

Response Example

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

Case 3: Invalid Parameters

Steps

  • Invalid per_page (too large) or sort_by (unsupported)
  • Response: 400 Bad Request

Response Example

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

Error Handling

  • 400 Bad Request: invalid query parameters
  • 429 Too Many Requests: rate limiting for public endpoint
  • 500 Internal Server Error: unexpected errors (logged)

Additional Notes

  • Public endpoint: no authentication required
  • Return only safe, public fields (no internal identifiers)
  • Results may be cached for short TTL to improve performance
  • Keep per_page small to ensure fast initial load on landing page