Product normalizers
Product includes two normalizers:
normalizeProduct: This function is used to map SAPProductintoSfProduct, which includes a full product detailsnormalizeProductCatalogItem: This function is used to map SAPProductintoSfProductCatalogItem, which includes only basic product details, needed to display a product in a product catalog
Parameters
normalizeProduct
| Name | Type | Default value | Description |
|---|---|---|---|
context | NormalizeProductContext | Context needed for the normalizer. transformImageUrl is added to transform product images urls, and sku to specify a product variant | |
product | Product | SAP Product |
normalizeProductCatalogItem
| Name | Type | Default value | Description |
|---|---|---|---|
context | NormalizeProductCatalogItemContext | Context needed for the normalizer. transformImageUrl is added to transform product images urls | |
product | Product | SAP Product |
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 addCustomFields API. In the following example we extend the normalizeProduct with classifications field which is available on SAP Product and normalizeProductCatalogItem with description field.
import { normalizers } from "@vsf-enterprise/unified-api-sapcc";
export const unifiedApiExtension = createUnifiedExtension({
normalizers: {
addCustomFields: [
{
normalizeProduct: (context, product) => {
const { quantityLimit } = normalizers.normalizeProduct(context, product);
return {
classifications: product.classifications,
isSmallQuantityLimit: quantityLimit && quantityLimit <= 10,
}
},
normalizeProductCatalogItem: (context, product) => ({
description: product.description,
}),
},
],
},
config: {
...
},
});
Since both normalizers accept SAP Product as a second argument, you may also use the same approach to use same representation for both SfProduct and SfProductCatalogItem models.
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 "@/helpers";
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((context, product) => {
const { allOptions, currentOption } = getOptions(product, context.sku);
const attributes = getAttributes(context, currentOption?.variantOptionQualifiers ?? []);
const variants = normalizeVariants(context, allOptions);
const { id, sku, name, slug, price, primaryImage, rating, quantityLimit } =
context.normalizers.normalizeProductCatalogItem(product);
const { gallery } = createSfImages(context, product.images);
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(
context: NormalizerContext,
variants: VariantOption[],
): SfProduct["variants"] {
return variants.map((variant) => normalizeVariant(context, variant));
}
function normalizeVariant(context: NormalizerContext, variant: VariantOption): SfProductVariant {
const id = variant.code as string;
return {
id,
sku: id,
slug: slugify(id),
name: null,
quantityLimit: maybe(variant.stock?.stockLevel),
attributes: getAttributes(context, variant.variantOptionQualifiers ?? []),
};
}
function getAttributes(context: NormalizerContext, optionQualifiers: VariantOptionQualifier[]) {
return optionQualifiers
.map((optionQualifier) => context.normalizers.normalizeAttribute(optionQualifier))
.filter(Boolean);
}