Skip to content

[REX-3084] Add getRecommendationPage for the recommendations page endpoint - #490

Draft
TimDumol wants to merge 2 commits into
Constructor-io:masterfrom
TimDumol:rex-3084-page-results
Draft

TimDumol wants to merge 2 commits into
Constructor-io:masterfrom
TimDumol:rex-3084-page-results

Conversation

@TimDumol

Copy link
Copy Markdown

Adds recommendations.getRecommendationPage(pageId, parameters, networkParameters) for GET /recommendations/v1/pages/{page_id} (API reference). A page returns every pod configured on it in one request, deduplicated across pods server-side.

What it does

  • Shared parameters: itemIds, variationId, section, term, numResults, filters, filterMatchTypes, preFilterExpression, fmtOptions, hiddenFields, variationsMap. They use the same wire format as getRecommendations, plus the session, user, segment and test-cell parameters.

  • podOverrides: { [podId]: { numResults, filters, filterMatchTypes, preFilterExpression, fmtOptions, hiddenFields, variationsMap } } is sent in bracket notation, e.g. pod_overrides[complete_the_look][filters][color]=red. Each value uses the same encoding as the top-level param: filters and fmt_options as nested brackets, pre_filter_expression and variations_map as JSON strings. An override replaces the page-wide value for that pod; it is not merged. Page-wide keys inside an override (e.g. itemIds) are rejected client-side with a clear error. The server would return 400 for them anyway.

  • Tracking: per-pod result_id. The top-level result_id identifies the page request and is not a beacon id. For each pod in response.pods[], the method:

    • stamps pod.result_id onto each of that pod's results, the way getRecommendations stamps its result_id
    • dispatches cio.client.recommendations.getRecommendations.completed with { request: { ...pod.request, pod_id }, response: pod.response, result_id: pod.result_id }, which is exactly the single-pod shape. The beacon's event-driven tracker keys on detail.request.pod_id and detail.response.results (autocomplete-ui src/tracker.js), so each pod is beaconed with its own result_id and pod_id.
  • Also dispatches a page-level cio.client.recommendations.getRecommendationPage.completed event with the full response.

  • Types: RecommendationPageParameters, RecommendationPagePodOverride, RecommendationPageResponse, RecommendationPagePod.

  • fmt_options replace semantics: hiddenFields is sent inside fmt_options, and an override replaces the page-wide value wholesale. So an override that sets only hiddenFields drops the page-wide fmtOptions for that pod, and vice versa.

Back-compat

getRecommendations behavior, events and URLs are unchanged. The session/user/test-cell block moved into a shared helper. I generated getRecommendations URLs from origin/master and from this branch with the same inputs (all params incl. hiddenFields, variationsMap, preFilterExpression, numResults=0, user/segments/test cells; no params; hiddenFields only), and they are byte-identical apart from _dt. No dist/, docs/ or version changes.

Testing

  • npm run lint: clean
  • npm run test:types (tsd): passes, with new page type tests
  • New mocked specs (getRecommendationPage, stubbed fetch, no network): 10 passing. They cover the URL/path, shared params, bracket encoding of pod_overrides (incl. array filters, num_results=0, JSON pre_filter_expression/variations_map, fmt_options + hiddenFields), no mutation of a shared fmtOptions, per-pod result_id stamping (page id never used), per-pod getRecommendations.completed events with request.pod_id, the page event, and the rejections (malformed response, missing pageId, page-wide key in override, variationId without itemIds).
  • The same specs pass against the bundled (BUNDLED=true) and ESM (BUNDLED_VARIANT=esm) builds.
  • cspell: no new issues (3 pre-existing in src/types/tests/*.test-d.ts).
  • Live tests are added in describe.skip('getRecommendationPage - live'). The page endpoint is not yet enabled on the test index, and the test index has no page configured (/recommendations/v1/pages/pdp_b2c returns 404).
  • I did not run the existing live suite locally (no TEST_REQUEST_API_KEY); CI will.

Blocked / follow-ups

  • Live tests need the page endpoint enabled on the test index and a page configured there.
  • constructorio-ui-recommendations will use this method; its client peer-dependency floor must be raised once this is released.

🤖 Generated with Claude Code

TimDumol and others added 2 commits October 10, 2026 20:29
…point

Calls GET /recommendations/v1/pages/{page_id}. Shared parameters use the
same wire format as getRecommendations; podOverrides are sent as
pod_overrides[<pod_id>][<param>] in bracket notation.

Each pod's own result_id is stamped onto that pod's results, and one
recommendations.getRecommendations.completed event is dispatched per pod
(with request.pod_id set), so event-driven tracking beacons each pod with
its own result_id. The top-level result_id identifies the page request and
is not used for tracking. A page-level
recommendations.getRecommendationPage.completed event is also dispatched.

getRecommendations output is unchanged; the session/user parameter block
is shared through a helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant