Working with Facets
Learn how to configure your middleware to to customize facet types and filter facets
Facets are a part of every storefront, allowing customers to deeply filter through products using certain attributes.
The Unified Data Layer provides an SfFacet
interface that each unified integration's normalizer will return.
export interface SfFacet {
label: string;
name: string;
values: SfFacetItem[];
// set by getFacetType method
type: Maybe<SfFacetType | (string & Record<never, never>)>;
}
We can customize how this SfFacet
object is created by using the middleware configuration.
Middleware Configuration
Using the middleware configuration, you can customize how the type of each facet is normalized and also filter out unwanted facets from your API responses.
Customizing SfFacet type
The type
property in the SfFacet
object can be set using the getFacetType
method.
This method is used by your integration when normalizing an object to match the SfFacet
data structure. The implementation of this method will change depending on the platform you're using and the facets you want to customize.
getFacetType
accepts the raw facet object from your e-commerce backend and returns either an existing SfFacetType
or a custom string.
// middleware.config.ts
import { SfFacetTypes } from "@vsf-enterprise/unified-api-[Integration]";
export const unifiedApiExtension = createUnifiedExtension<Context>()({
normalizers,
apiMethods: {
...methods<typeof normalizers>(),
},
config: {
getFacetType: (facet) => {
if (facet.facet === "color") {
return "COLOR";
}
if (facet.facet === "size") {
return "SIZE";
}
return SfFacetTypes.MULTI_SELECT;
},
},
});
If you don't provide a custom getFacetType
method, the default value will depend on the Unified Integration that you're using. You can find the default function in your integration's normalizeFacet
method.
Filtering facets
Sometimes, your backend may return certain facets that you don't want included. You can filter out unwanted facets using the filterFacets
configuration and provide filtering condition based on raw facet input.
For example, when using the searchProducts
Unified Method, all of the facets coming from the search results are also returned. But you may want to filter some of them out, such as facets that are also categories. For cases like this, you can use the filterFacets
configuration.
filterFacets
runs before normalization, so the input is the raw facet object from your e-commerce backend and the output is a boolean value that determines whether the facet should be included in the response.
// middleware.config.ts
export const unifiedApiExtension = createUnifiedExtension<Context>()({
normalizers,
apiMethods: {
...methods<typeof normalizers>(),
},
config: {
filterFacets: (facet) => facet.category === false,
},
});
As a simplified example of how filterFacets
is used, the below code shows part of a standard integration's searchProducts
implementation.
return {
// ...
facets: rawFacets // raw facet array following your backends data structures
.filter((facet) => filterFacets(facet))
.map((facet) => normalizeFacet(facet, normalizerContext))
// ...
}
If you don't provide a custom filterFacets
method, all facets will be included in the response.
Example Usage
After configuring the middleware, you can use the Unified Data Model's SfFacet
data structure in your storefront application.
Knowing the possible values of SfFacet.type
can be helpful for iterating over facets to display filters, queries, tags, and more.
// components/CategoryFilters.tsx
export function CategoryFilters() {
// ...
return (
<div>
{facets.map((facet) => {
switch (facet.type) {
case "SIZE": {
return <FilterSize facet={facet} key={facet.name} />;
}
case "COLOR": {
return <FilterColor facet={facet} key={facet.name} />;
}
case "SINGLE_SELECT": {
return <FilterRadio facet={facet} key={facet.name} />;
}
default: {
return <FilterCheckbox facet={facet} key={facet.name} />;
}
}
})}
</div>
);
}