Catalog query

Catalog query flow: from the frontend to the catalog microservice, passing through the database and the caching layer to optimize responses.

Why the catalog query is a representative flow

The catalog query is one of the most frequent flows in any commerce or management application. It is a read-intensive case: many users query the same data, the data changes infrequently, and response speed directly impacts the user experience.

This flow illustrates how the architecture handles optimized reads with caching and how the BFF adapts the data for the frontend.

The complete flow

sequenceDiagram
    participant FE as Frontend
    participant GW as API Gateway
    participant BFF as BFF
    participant CACHE as Caché
    participant MS as ms-catalog
    participant DB as Catalog DB

    FE->>GW: GET /catalog/products?category=electronics
    GW->>GW: Auth, rate limiting
    GW->>BFF: Forward

    BFF->>CACHE: ¿Datos en caché?
    alt Cache HIT
        CACHE-->>BFF: Datos cacheados
    else Cache MISS
        BFF->>MS: GET /products?category=electronics
        MS->>DB: SELECT * FROM products WHERE category = ...
        DB-->>MS: Resultados
        MS-->>BFF: Lista de productos
        BFF->>CACHE: Guardar en caché (TTL: 5 min)
    end

    BFF->>BFF: Transformar para UI
    BFF-->>GW: Respuesta formateada
    GW-->>FE: 200 OK + productos

What each layer does

Frontend

  1. The user navigates to a category or uses the search bar
  2. The frontend builds the request with filters (category, price, sorting)
  3. It sends the request to the Gateway
  4. It receives the products and renders them in a grid or list
  5. It may implement pagination or infinite scroll

API Gateway

  1. Validates the user’s JWT token
  2. Applies rate limiting (catalog queries can be very frequent)
  3. Routes to the BFF

BFF

The BFF is where most of the optimization happens:

  1. Receives the request with the frontend’s filters
  2. Checks the cache to see if it already has the data
  3. On a cache hit, it returns the cached data directly
  4. On a cache miss, it invokes the catalog microservice
  5. Stores the response in the cache with an appropriate TTL
  6. Transforms the data into the format the frontend needs

Catalog microservice (ms-catalog)

  1. Receives the query with the filters
  2. Builds the query against the database
  3. Applies pagination, sorting, and filters
  4. Returns the products with their domain data

Database

  • Stores products, categories, prices, stock
  • Has indexes optimized for the most frequent queries
  • May use materialized views for complex queries

The caching layer in detail

Where to place the cache

There are several options, and they can be combined:

LocationAdvantageDisadvantage
BFF (Redis/Memcached)Reduces calls to the microserviceRequires invalidation
MicroserviceTransparent to the BFFNetwork latency still exists
CDN / GatewayVery fast for static contentHard to invalidate
Frontend (local)InstantPotentially stale data

In this architecture, the main cache lives in the BFF because it is the point where transformation and invalidation can be controlled best.

Invalidation strategy

The catalog cache is invalidated in two ways:

By TTL (Time To Live): each entry has a lifespan (for example, 5 minutes). After that time, it is considered stale and the microservice is queried again.

By event: when the catalog microservice updates a product, it publishes a ProductUpdated event. The BFF listens for that event and invalidates the affected cache entries.

sequenceDiagram
    participant ADMIN as Admin
    participant MS as ms-catalog
    participant EB as Event Bus
    participant BFF as BFF
    participant CACHE as Caché

    ADMIN->>MS: PUT /products/123 (actualizar precio)
    MS->>MS: Actualizar en DB
    MS->>EB: Publicar ProductUpdated
    EB->>BFF: Evento ProductUpdated
    BFF->>CACHE: Invalidar entradas relacionadas

Cache key design

Cache keys must be deterministic and reflect the query parameters:

catalog:products:category=electronics:sort=price:page=1
catalog:products:category=electronics:sort=price:page=2
catalog:product:123

Transformation in the BFF

The microservice returns full domain data, but the frontend does not need all of it. The BFF transforms it:

Microservice response:

{
  "id": "prod-123",
  "internalSku": "SKU-2024-001",
  "name": "Laptop Pro",
  "description": "...",
  "priceInCents": 99900,
  "currency": "USD",
  "stockQuantity": 45,
  "warehouseLocation": "A-12-3",
  "categoryId": "cat-electronics",
  "createdAt": "2024-01-01T00:00:00Z",
  "updatedAt": "2024-01-15T10:00:00Z"
}

BFF response to the frontend:

{
  "id": "prod-123",
  "name": "Laptop Pro",
  "description": "...",
  "price": "$999.00",
  "inStock": true,
  "category": "Electrónica",
  "imageUrl": "/images/prod-123.jpg"
}

The BFF strips out internal data (internalSku, warehouseLocation), formats the price, simplifies stock to a boolean, and resolves the category to its human-readable name.

Pagination and performance

For large catalogs, pagination is essential:

  • The frontend sends page and pageSize
  • The microservice applies LIMIT and OFFSET in the query
  • The response includes pagination metadata (totalItems, totalPages, currentPage)
  • Each page is cached independently

Error scenarios

Microservice unavailable

If the catalog microservice is down but there is data in the cache (even if expired), the BFF can return the stale data with a header indicating it is stale. This is better than showing the user an error.

Cache unavailable

If Redis is down, the BFF simply queries the microservice directly. Latency increases but the flow does not break.

Query with no results

This is not an error. The microservice returns an empty list and the frontend displays a “No products found” message.

Summary

The catalog query shows how the architecture optimizes read-intensive flows. Caching in the BFF reduces the load on the microservice and the database, while event-based invalidation keeps the data reasonably fresh. The BFF transforms the domain data into the format the frontend needs, maintaining the separation of concerns between layers.