rudra-js

parseRecommendationRequest

import { parseRecommendationRequest } from '@rudra-js/a2ui/server';

Call parseRecommendationRequest in your endpoint to check the hints the A2UI component sends.

parseRecommendationRequest(value: unknown) => RecommendationRequest

Reference

parseRecommendationRequest(value)

Parameters

  • value: The request body, parsed from JSON.

Returns

A RecommendationRequest holding the hints that were sent. When the body doesn't fit, it throws a ZodError instead.

Caveats

  • It accepts only currentSku, currentCategory, searchQuery and maxItems. A body that sets the shopper, the candidates or any other field throws.
  • Each hint has the same limits as the matching field in context. A maxItems of 40 throws, because the most is 12.
  • Anyone can call your endpoint with any hints. With a provider, each new category or maxItems it gets is a new model call. With generation: 'per-shopper', so is each new shopper, SKU and search. Rate-limit the endpoint.

Usage

Building the block in your endpoint

The endpoint checks the hints, builds the block with core, and sends it back with the products it may show.

import { createComponentGenerator, parseTrackingInput } from '@rudra-js/core';
import {
  fitRecommendationRequest,
  parseRecommendationRequest,
  type RecommendationRequest,
  type RecommendationResult,
} from '@rudra-js/a2ui/server';
import { candidatesFor, shopperFor } from './your-shop.js';

const generator = createComponentGenerator({ provider: null });

export async function POST(request: Request): Promise<Response> {
  let asked: RecommendationRequest;
  try {
    asked = parseRecommendationRequest(await request.json());
  } catch {
    return new Response('Bad request', { status: 400 });
  }

  const shopper = await shopperFor(request);
  const candidates = await candidatesFor(shopper);
  const hints = fitRecommendationRequest(asked, candidates);
  const input = parseTrackingInput({
    user: { id: shopper.id },
    context: { surface: 'assistant', locale: shopper.locale, ...hints },
    candidates,
    signals: shopper.signals,
  });
  const spec = await generator.generate(input);

  const result: RecommendationResult = { spec, products: input.candidates, bundles: input.bundles };
  return Response.json(result);
}

A body that fails parseRecommendationRequest gets a 400.

shopperFor and candidatesFor stand for the session and catalog code you already have. The shopper, the signals and the candidates never come from the request body.

provider: null calls no model. Pass your own provider to turn the model on.

In Next.js, save this file as app/api/recommendations/route.ts.