Freelance2026
Aments Storefront
A server-rendered Next.js storefront with a strict Route → Query → Mapper → UI data architecture.
- Rendering
- SSR
- Data layers
- 4
- i18n
- Server-side lang
01Overview
An e-commerce frontend for a backend whose JSON shape is not under the frontend's control. The goal: UI components always read stable keys, even when the API changes.
02The problem
When components read raw API fields directly, every backend rename breaks the UI in many places, and components fill up with fallback logic like raw?.name ?? raw?.title ?? "".
03Architecture
Each layer has one responsibility, and only the mapper knows what the backend JSON looks like.
UI
Sections & cards
Read stable keys only - no fallbacks
Route
Server page.jsx
Resolve language, call queries, pass props
Query
*.query.js
Request + extract + map + filter
Mapper
*.mapper.js
Raw JSON → UI shape with defaults
Transport
ApiService
HTTP client
apiRoutes
Endpoint constants
04Components
Mappers
The only place that knows the API shape
- Start from a defaults object, copy known fields, derive display values (counts, hrefs).
Queries
One function per endpoint
- Remove repeated request/extract code and drop invalid items before they reach the UI.
Routes
Server-side composition
- Fetch on the server with the user's language and fall back to an empty list on failure, so a broken endpoint never breaks the page.
05How it works
- 1
Route
The server page resolves the language and calls a query.
- 2
Query
Requests the endpoint via ApiService and extracts res.data.data.
- 3
Mapper
Converts each raw item to the stable UI shape.
- 4
UI
Receives props and renders cat.name, cat.image, cat.items, cat.href.
06Technical deep dives
A mapper with defaults
If the backend renames orderCount, only this function changes - every component keeps reading items.
const PopularCategoryDefaults = {
id: null, name: "", image: "", items: "(0 Items)", href: "/products",
};
export function mapPopularCategory(raw = {}) {
return {
...PopularCategoryDefaults,
id: raw?.id ?? PopularCategoryDefaults.id,
name: raw?.name ?? PopularCategoryDefaults.name,
image: raw?.image ?? PopularCategoryDefaults.image,
items: `(${Number(raw?.orderCount ?? 0) || 0} Items)`,
href: raw?.id != null
? `/products?categoryId=${encodeURIComponent(String(raw.id))}`
: PopularCategoryDefaults.href,
};
}07Design decisions
Anti-corruption layer
The mapper isolates the UI from an external API - a classic domain-driven design pattern applied to the frontend.
Fail soft on the server
A failing query returns an empty list; the page still renders.
08Tech stack
- Frontend
- Next.js (App Router)ReactJavaScriptBootstrap gridSSR
Next case study
Diaspor.org
A multi-tenant publishing platform: a branded news site for every diaspora organisation, and one national feed.