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
- The user navigates to a category or uses the search bar
- The frontend builds the request with filters (category, price, sorting)
- It sends the request to the Gateway
- It receives the products and renders them in a grid or list
- It may implement pagination or infinite scroll
API Gateway
- Validates the user’s JWT token
- Applies rate limiting (catalog queries can be very frequent)
- Routes to the BFF
BFF
The BFF is where most of the optimization happens:
- Receives the request with the frontend’s filters
- Checks the cache to see if it already has the data
- On a cache hit, it returns the cached data directly
- On a cache miss, it invokes the catalog microservice
- Stores the response in the cache with an appropriate TTL
- Transforms the data into the format the frontend needs
Catalog microservice (ms-catalog)
- Receives the query with the filters
- Builds the query against the database
- Applies pagination, sorting, and filters
- 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:
| Location | Advantage | Disadvantage |
|---|---|---|
| BFF (Redis/Memcached) | Reduces calls to the microservice | Requires invalidation |
| Microservice | Transparent to the BFF | Network latency still exists |
| CDN / Gateway | Very fast for static content | Hard to invalidate |
| Frontend (local) | Instant | Potentially 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
pageandpageSize - The microservice applies
LIMITandOFFSETin 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.