Product normalizers
Product includes two normalizers:
normalizeProduct
: This function is used to map SAPProduct
intoSfProduct
, which includes a full product detailsnormalizeProductCatalogItem
: This function is used to map SAPProduct
intoSfProductCatalogItem
, which includes only basic product details, needed to display a product in a product catalog
Parameters
normalizeProduct
Name | Type | Default value | Description |
---|---|---|---|
product | Product | SAP Product | |
ctx | NormalizeProductContext | Context needed for the normalizer. transformImageUrl is added to transform product images urls, and sku to specify a product variant |
normalizeProductCatalogItem
Name | Type | Default value | Description |
---|---|---|---|
product | Product | SAP Product | |
ctx | NormalizeProductCatalogItemContext | Context needed for the normalizer. transformImageUrl is added to transform product images urls |
Extending
The SfProduct
model is returned from GetProductDetails
method. The SfProductCatalogItem
model is returned from GetProducts
method. If any of these models don't contain the information you need for your Storefront, you can extend its logic using the defineNormalizers
function. In the following example we extend the normalizeProduct
with classifications
field which is available on SAP Product and normalizeProductCatalogItem
with description
field.
import { normalizers as normalizersSAP, defineNormalizers } from "@vsf-enterprise/unified-api-sapcc";
const normalizers = defineNormalizers<typeof normalizersSAP>()({
...normalizersSAP,
normalizeProduct: (product, context) => ({
...normalizersSAP.normalizeProduct(product, context),
classifications: product.classifications,
}),
normalizeProductCatalogItem: (product, context) => ({
...normalizersSAP.normalizeProductCatalogItem(product, context),
description: product.description,
}),
});
Since both normalizers accepts SAP Product
as a first argument, you may also use the same approach to use same representation for both SfProduct
and SfProductCatalogItem
models.
import { normalizers as normalizersSAP } from "@vsf-enterprise/unified-api-sapcc";
import { defineNormalizers } from "@vue-storefront/unified-data-model";
const normalizers = defineNormalizers<typeof normalizersSAP>()({
...normalizersSAP,
normalizeProduct: (product, context) => ({
...normalizersSAP.normalizeProduct(product, context),
}),
normalizeProductCatalogItem: (product, context) => ({
...normalizersSAP.normalizeProduct(product, context),
}),
});
However in this case you should be aware that SfProductCatalogItem
will contain all the fields from SfProduct
model and it will affect the performance of the catalog page.
Source
The normalizeProduct
and normalizeProductCatalogItem
function consists of several smaller normalizers such as normalizeImage
, normalizeDiscountablePrice
, and more, which you can override as well.
import type { NormalizerContext } from "@/normalizers/types";
import { maybe, slugify } from "@shared/utils";
import type { VariantOption, VariantOptionQualifier } from "@vsf-enterprise/sapcc-types";
import type { SfProduct, SfProductVariant } from "@vue-storefront/unified-data-model";
import sanitizeHtml from "sanitize-html";
import { defineNormalizer } from "../defineNormalizer";
import { createSfImages } from "./images";
import { getOptions } from "@/normalizers/__internal__";
export const normalizeProduct = defineNormalizer.normalizeProduct((product, ctx) => {
const { allOptions, currentOption } = getOptions(product, ctx.sku);
const attributes = getAttributes(currentOption?.variantOptionQualifiers ?? [], ctx);
const variants = normalizeVariants(allOptions, ctx);
const { id, sku, name, slug, price, primaryImage, rating, quantityLimit } =
ctx.normalizers.normalizeProductCatalogItem(product);
const { gallery } = createSfImages(product.images, ctx);
const description = product.description
? sanitizeHtml(product.description)
: product.summary
? sanitizeHtml(product.summary)
: null;
return {
id,
sku,
name,
slug,
price,
primaryImage,
rating,
quantityLimit,
attributes,
variants,
description,
gallery,
};
});
function normalizeVariants(
variants: VariantOption[],
ctx: NormalizerContext,
): SfProduct["variants"] {
return variants.map((variant) => normalizeVariant(variant, ctx));
}
function normalizeVariant(variant: VariantOption, ctx: NormalizerContext): SfProductVariant {
const id = variant.code as string;
return {
id,
sku: id,
slug: slugify(id),
name: null,
quantityLimit: maybe(variant.stock?.stockLevel),
attributes: getAttributes(variant.variantOptionQualifiers ?? [], ctx),
};
}
function getAttributes(optionQualifiers: VariantOptionQualifier[], ctx: NormalizerContext) {
return optionQualifiers
.map((optionQualifier) => ctx.normalizers.normalizeAttribute(optionQualifier))
.filter(Boolean);
}