Broadleaf Microservices

A Product Detail Page (PDP) Walkthrough

In this walkthrough, we’ll be examining how we built the commerce app’s Product Detail Page (PDP). We will go through:

  1. Querying Products.

    • We will go over the required parameters and how to query the required information through the commerce-sdk and the REST API.

  2. Page Overview (Basic)

    • We will discuss page design specifically around a single product.

Product Page

Prerequisite Information

Prior to loading content specific to the requested product we need to know, certain information prior, Specifically:

  1. Resolve the tenant and application

  2. Send a request to authenticate the user and determine permissions, whether as anonymous or signed-in

  3. What Product are you requesting

    • Products can be requested by two different methods, by url or by product id

Querying Products.

So before querying there are only two things required, first is the Application Context, because we need to what tenant and application to know where to query the document from. The other needed information is a way to identity the product, which can be the product’s id or the product url/slug. Depending on which will determine on the endpoint that will be queried.

By ID

METHOD

URL

SDK

By Product ID

GET

/products/<PRODUCT_ID>

getProductById()

Details can be found in the Products Details OpenAPI Documentation

Example 1. How to query by product id in the SDK
import { ClientOptions } from '@broadleaf/commerce-core';
import { BrowseClient } from '@broadleaf/commerce-browse';

async function getProductDetails(productId: string, options: ClientOptions) {
    const client = new BrowseClient(options);
    return client.getProductById(productId);
}

Alternatively client.getProduct({productIds: [<PRODUCT_ID>]}) can be used, however the connical method for query a single product by id is getProductById

By URL

METHOD

URL

SDK

By Product URL

GET

/api/catalog/product-details?productUris=<PRODUCT_URL>

getProductByURL()

Details can be found in the Products Details OpenAPI Documentation

Example 2. How to query by product id in the SDK
import { ClientOptions } from '@broadleaf/commerce-core';
import { BrowseClient } from '@broadleaf/commerce-browse';

// example: `const productSlug = '/hot-sauces/green-host'`
async function getProductDetails(productSlug: string, options: ClientOptions) {
    const client = new BrowseClient(options);
    return client.getProductByURL(productSlug);
};

Alternatively client.getProduct({productUris: [<PRODUCT_URL>]}) can be used, however the connical method for query a single product by URL is getProductByUrl

Product Details Response

The Response return is a Product object:

Example 3. Response Payload
const product = {
  "id": "product4",
  "sku": "HS-HHS-20",
  "priceInfo": {
    "target": {
      "targetId": "HS-HHS-20",
      "targetType": "SKU",
      "priceableFields": {
        "basePrice": {
          "amount": 8.99,
          "currency": "USD"
        }
      },
      "attributes": {
        "skuRef": {
          "id": "product4"
        }
      }
    },
    "price": {
      "amount": 8.99,
      "currency": "USD"
    },
    "priceType": "basePrice",
    "priceTypeDetails": {
      "basePrice": {
        "type": "basePrice",
        "bestPrice": {
          "amount": 8.99,
          "currency": "USD"
        },
        "priceDetails": {}
      }
    }
  },
  "currency": "USD",
  "options": [],
  "variants": [],
  "includedProducts": [],
  "promotionalProducts": {},
  "assets": [
    {
      "tags": [],
      "primary": true,
      "contentUrl": "https://admin.blcdemo.com/api/asset/content/Hoppin-Hot-Sauce-Bottle.jpg?contextRequest=%7B%22forceCatalogForFetch%22:false,%22tenantId%22:%225DF1363059675161A85F576D%22%7D",
      "sorted": true,
      "altText": "Bottle of Hoppin' Hot Sauce",
      "productId": "product4",
      "provider": "BROADLEAF",
      "tenantId": "5DF1363059675161A85F576D",
      "id": "product4_primary",
      "type": "IMAGE",
      "title": "Bottle of Hoppin' Hot Sauce",
      "url": "/Hoppin-Hot-Sauce-Bottle.jpg",
      "parentId": "product4"
    }
  ],
  "primaryAsset": {
    "tags": [],
    "primary": true,
    "contentUrl": "https://admin.blcdemo.com/api/asset/content/Hoppin-Hot-Sauce-Bottle.jpg?contextRequest=%7B%22forceCatalogForFetch%22:false,%22tenantId%22:%225DF1363059675161A85F576D%22%7D",
    "sorted": true,
    "altText": "Bottle of Hoppin' Hot Sauce",
    "productId": "product4",
    "provider": "BROADLEAF",
    "tenantId": "5DF1363059675161A85F576D",
    "id": "product4_primary",
    "type": "IMAGE",
    "title": "Bottle of Hoppin' Hot Sauce",
    "url": "/Hoppin-Hot-Sauce-Bottle.jpg",
    "parentId": "product4"
  },
  "activeStartDate": "2021-04-27T18:41:40.120Z",
  "keywords": [],
  "description": "Tangy, ripe cayenne peppers flow together with garlic, onion, tomato paste and a hint of cane sugar to make this a smooth sauce with a bite. Wonderful on eggs, poultry, pork, or fish, this sauce blends to make rich marinades and soups.",
  "metaDescription": "Tangy, ripe cayenne peppers flow together with garlic, onion, tomato paste and a hint of cane sugar to make this a smooth sauce with a bite. Wonderful on eggs, poultry, pork, or fish, this sauce blends to make rich marinades and soups.",
  "fulfillmentFlatRates": {},
  "eligibleForPickup": false,
  "onSale": false,
  "discountable": true,
  "parentCategories": [
    {
      "id": "category1",
      "name": "Hot Sauces",
      "url": "/hot-sauces"
    },
    {
      "id": "category7",
      "name": "Top Sellers",
      "url": "/"
    }
  ],
  "reviewsSummary": {
    "numberOfReviews": 0
  },
  "inventoryType": "PHYSICAL",
  "merchandisingProduct": false,
  "active": true,
  "individuallySold": true,
  "uri": "/hot-sauces/hoppin-hot-sauce",
  "searchable": true,
  "tags": [
    "z9",
    "salsa"
  ],
  "inventoryCheckStrategy": "NEVER",
  "inventoryReservationStrategy": "NEVER",
  "metaTitle": "Hoppin' Hot Sauce Test 3",
  "name": "Hoppin' Hot Sauce Test 3",
  "online": true,
  "attributes": {},
  "availableOnline": true,
  "breadcrumbs": [
    {
      "label": "Hoppin' Hot Sauce Test 3"
    }
  ]
}

Page Overview (Basic)

We will discuss page design specifically around a single product. so given that we have a valid product object return to us, we can begin constructing a simple product page.

Product Page

from the image above we can see that there are 5 pieces of information that we need from the product object that we need to display. specifically the: description, name, price, sku, and image(s).

for the name and description and sku, we can obtain as top-level properties. We then use this to populated their respective components

// let product be a non-null Product object
const {name, description, sku} = product;

price is located in pricingInfo and it is a object that contains amount and currency.

// let product be a non-null Product object
const { price } = product.pricingInfo;
console.log(`${price.amount} ${price.currency}`) // '8.99 USD'

Image assets are split between two properties; assets, and primaryAsset. for the page we use the assets array that is iterated though to display

product.assets is a list of image resources, which contains a Asset object that contains contentUrl, altText that are to display the image. This is not to be confused with primaryAsset which is a single object that is considered the main object when only on is displayed. primaryAsset will have a matching object in assets

{
"assets" : [
    {
      "tags": [],
      "primary": true,
      "contentUrl": "https://admin.blcdemo.com/api/asset/content/Hoppin-Hot-Sauce-Bottle.jpg?contextRequest=%7B%22forceCatalogForFetch%22:false,%22tenantId%22:%225DF1363059675161A85F576D%22%7D",
      "sorted": true,
      "altText": "Bottle of Hoppin' Hot Sauce",
      "productId": "product4",
      "provider": "BROADLEAF",
      "tenantId": "5DF1363059675161A85F576D",
      "id": "product4_primary",
      "type": "IMAGE",
      "title": "Bottle of Hoppin' Hot Sauce",
      "url": "/Hoppin-Hot-Sauce-Bottle.jpg",
      "parentId": "product4"
    }
  ],
  "primaryAsset": {
    "tags": [],
    "primary": true,
    "contentUrl": "https:/admin.blcdemo.com/api/asset/content/Hoppin-Hot-Sauce-Bottle.jpg?contextRequest=%7B%22forceCatalogForFetch%22:false,%22tenantId%22:%225DF1363059675161A85F576D%22%7D",
    "sorted": true,
    "altText": "Bottle of Hoppin' Hot Sauce",
    "productId": "product4",
    "provider": "BROADLEAF",
    "tenantId": "5DF1363059675161A85F576D",
    "id": "product4_primary",
    "type": "IMAGE",
    "title": "Bottle of Hoppin' Hot Sauce",
    "url": "/Hoppin-Hot-Sauce-Bottle.jpg",
    "parentId": "product4"
  }
}
// let product be a non-null Product object
const { price } = product.pricingInfo;
console.log(`${price.amount} ${price.currency}`) // '8.99 USD'