2 min read
Enrich contracts with custom data
This article based on Poq.ApiTemplate.Node, it would be easier to understand if you set up you environment according to the guide: Your first BFC
This type of customization is mostly used across projects and there are at least a few ways how to do that. Given examples will help you to understand when and how to do that.
First of all, let's define when and how question to describe the use case of contract customization:
When do we need to enrich existing contracts with custom data?
By default the Poq contracts carry essential information, however, in some cases extension is required to provide a great user experience for clients.
Let's imagine you want to add indicators to the product that depicts whether:
- it contains lead;
- it's certified according to some standard ISO-XXXX;
These specific requirements could be reached in several ways: we can add this information in the description to a product, but if the specific indication is necessary then the most suitable option would be to extend the contract with two fields accordingly.
Follow the next section to find out how to do that.
How to enrich/extend an existing contracts?
Let's explore the structure of product contract first:
export declare class Product extends PoqContract { readonly id: string; readonly appIdentifier: string; readonly details: ProductDetails; readonly variants: Map<string, ProductVariant>; readonly categoryIds: string[] | undefined; readonly forms: Form[] | undefined; readonly meta: ProductMeta | undefined; readonly promotion: Promotion | undefined; readonly review: CatalogueReview | undefined; readonly customData: Record<string, unknown> | undefined;}
Mobile application (default configuration) expects data to be presented in the form above. In that case we can add new fields by:
- Using standard OOP inheritance and extends the
Product
contract (further:Inheritance
); - Using
customData
field to store necessary information in there (further:CustomData
);
Approach | Pros | Cons |
---|---|---|
Inheritance | Standard OOP | Mobile client should be updated to support any new field |
Explicit semantics | ||
Explicit contract structure | ||
CustomData | Mobile client works with field out of the box (OOB) | Implicit structure. No strict typing |
Easy to extend with values |
Both ways are fine, however, CustomData
way is easier to utilize in practise.
Example
Task:
- As a user I want to see whether a product contains lead (on Product Details Page - PDP).
- As a user I want to see whether a product is certified by ISO-XXXX (PDP).
Let's assume your project is set up and ready for development, the ApiTemplate.Node is used to create the project.
In your IDE explore ./src/modules/product
folder (Expected folder tree is below).
./src/modules/product├── controllers│ ├── __tests__│ │ └── product-controller.integration-spec.ts│ ├── index.ts│ └── product.controller.ts├── dependency.factories.ts├── index.ts├── mappers│ ├── __tests__│ │ └── product-mapper.spec.ts│ ├── index.ts│ ├── interfaces│ │ ├── index.ts│ │ └── product-mapper.interface.ts│ └── product.mapper.ts├── product.module.ts└── services ├── __tests__ │ └── product-service.spec.ts ├── index.ts ├── interfaces │ ├── index.ts │ └── product-service.interface.ts └── product.service.ts
The first step is to identify what contracts we are going to extend.
The default set of contracts is provided by @poq/sdk
package, see: SDK API.
We're looking for a Product Contract and endpoints to check.
Endpoints can be found in product.controller.ts
file, the controller is using product.service.ts
to return products to an end-user.
If you open product.service.ts
you'll find that there are product.mapper.ts
in charge of forming product shape.
Open file of given product.mapper.ts
and check section with creation of Product
.
// This code is relevant to NODE ApiTemplate for SFCC-Based Apps.
// This is an example how-to add custom fields to custom data field// and only gives you an example how it could look like.
export class ProductMapper implements IProductMapper { ...
// Method ProductMapper#convertVariantsToPoqProduct convertVariantsToPoqProduct(appIdentifier: string, appConfig: AppConfig, sfccVariants: SfccProduct[]): Product { // Here we assume if at least one product contains lead we can say it for all variants const containsLead = sfccVariants.some((variant) => Boolean(variant.getPropertyValue('c_containsLead')));
// Here we assume if at least on product certified then all variants follow the same standard const certified = sfccVariants.find((variant) => variant.getPropertyValue('c_certified')) ?? 'None';
... return new Product({ ..., customData: { containsLead, certified } }); } ...}
In this example we assume the custom fields are available on your Salesforce cloud instance.
That's it. You added new fields to the contract.
For Salesforce objects are common to use c_
prefix before the custom field.
In SDK SFCC to read/write custom field values we could use getPropertyValue
/setPropertyValue
accordingly.
Check more detail here: API SDK SFCC.