All projects

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. 1

    Route

    The server page resolves the language and calls a query.

  2. 2

    Query

    Requests the endpoint via ApiService and extracts res.data.data.

  3. 3

    Mapper

    Converts each raw item to the stable UI shape.

  4. 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.

src/mappers/popular-category.mapper.jsjs
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.