Skip to main content

Build a Catalog Page

Query the product catalog from Propeller and fetch the data you need for a catalog page on your frontend. Run these queries in the GraphQL client you set up on the previous page.

Fetch the catalog

Use the products query to fetch a paginated catalog. The catalog can contain both clusters (products with variants) and standalone products, so the query uses inline fragments for both types.

This query fetches everything you need for a catalog page: product name, SKU, price, stock, slug (for URLs) and a thumbnail image.

query GetCatalog($input: ProductSearchInput) {
products(input: $input) {
page
itemsFound
pages
items {
... on Cluster {
clusterId
names {
value
}
class
slugs {
value
}
defaultProduct {
productId
sku
names(language: "NL") {
value
}
inventory {
totalQuantity
}
price(input: { taxZone: "NL" }) {
gross
net
}
media {
images(search: { sort: ASC, offset: 1 }) {
items {
alt(language: "NL") {
value
}
imageVariants(
input: {
transformations: {
name: "thumb"
transformation: {
width: 240
height: 240
fit: BOUNDS
bgColor: "transparent"
canvas: { width: 240, height: 240 }
}
}
}
) {
url
}
}
}
}
}
}
... on Product {
class
productId
sku
slugs {
value
}
names(language: "NL") {
value
}
inventory {
totalQuantity
}
price(input: { taxZone: "NL" }) {
gross
net
}
media {
images(search: { sort: ASC, offset: 1 }) {
items {
alt(language: "NL") {
value
}
imageVariants(
input: {
transformations: {
name: "thumb"
transformation: {
width: 240
height: 240
fit: BOUNDS
bgColor: "transparent"
canvas: { width: 240, height: 240 }
}
}
}
) {
url
}
}
}
}
}
}
}
}

Variables:

{
"input": {
"language": "NL",
"sortInputs": [
{
"field": "LAST_MODIFIED_AT",
"order": "DESC"
}
],
"page": 1,
"offset": 24
}
}

Expected result:

{
"data": {
"products": {
"page": 1,
"itemsFound": 36,
"pages": 2,
"items": [
{
"clusterId": 6,
"names": [{ "value": "Smooth Cylinder Pendant Spotlight" }],
"class": "CLUSTER",
"slugs": [{ "value": "smooth-cylinder-pendant-spotlight" }],
"defaultProduct": {
"productId": 75,
"sku": "SM-CYL-3K80-PSU",
"names": [{ "value": "Smooth Cylinder 3000K CRI80+ PSU" }],
"inventory": { "totalQuantity": 150 },
"price": { "gross": 189.0, "net": 228.69 },
"media": {
"images": {
"items": [
{
"alt": [{ "value": "Product image of Smooth Cylinder Pendant Spotlight" }],
"imageVariants": [{ "url": "https://media.helice.cloud/..." }]
}
]
}
}
}
},
{
"class": "PRODUCT",
"productId": 45,
"sku": "GT-HGW1",
"slugs": [{ "value": "hidden-glow-wall-washer" }],
"names": [{ "value": "Hidden Glow Wall Washer" }],
"inventory": { "totalQuantity": 278 },
"price": { "gross": 342.54, "net": 414.47 },
"media": {
"images": {
"items": [
{
"alt": [],
"imageVariants": [{ "url": "https://media.helice.cloud/..." }]
}
]
}
}
}
]
}
}
}

The offset field controls how many items per page. The page field controls which page to fetch. Use slugs for building product URLs in your frontend. See Core Concepts for more on how clusters and standalone products relate to each other.

Fetch a single product

When a user clicks a product in the catalog, fetch the full detail. Use the product query to look up a product by productId, sku or slug.

query GetProduct($productId: Int, $language: String) {
product(productId: $productId, language: $language) {
productId
sku
class
categoryId
names {
language
value
}
descriptions {
language
value
}
shortDescriptions {
language
value
}
manufacturer
manufacturerCode
inventory {
totalQuantity
}
price(input: { taxZone: "NL" }) {
gross
net
}
categoryPath {
name(language: "NL") {
value
}
}
media {
images(search: { sort: ASC, offset: 5 }) {
itemsFound
items {
alt(language: "NL") {
value
}
imageVariants(
input: {
transformations: {
name: "large"
transformation: {
width: 240
height: 240
fit: BOUNDS
bgColor: "transparent"
canvas: { width: 240, height: 240 }
}
}
}
) {
url
}
}
}
}
}
}

Variables:

{
"productId": 45,
"language": "NL"
}

Expected result:

{
"data": {
"product": {
"productId": 45,
"sku": "GT-HGW1",
"class": "PRODUCT",
"categoryId": 1736,
"names": [{ "language": "NL", "value": "Hidden Glow Wall Washer" }],
"descriptions": [
{
"language": "NL",
"value": "<p>Designed to provide soft, ambient lighting seamlessly integrated into walls</p>"
}
],
"shortDescriptions": [
{
"language": "NL",
"value": "<p>Designed to provide soft, ambient lighting seamlessly integrated into walls</p>"
}
],
"manufacturer": "ProLight Solutions",
"manufacturerCode": "GT-HGW1",
"inventory": { "totalQuantity": 278 },
"price": { "gross": 342.54, "net": 414.47 },
"categoryPath": [
{ "name": [{ "value": "PDM" }] },
{ "name": [{ "value": "Recessed" }] }
],
"media": {
"images": {
"itemsFound": 1,
"items": [
{
"alt": [],
"imageVariants": [{ "url": "https://media.helice.cloud/..." }]
}
]
}
}
}
}
}

Descriptions can contain HTML. The categoryPath returns the full breadcrumb from root to the product's category.

Search products

Use the same products query with a term to search across product names, SKUs, descriptions and manufacturer codes.

query SearchProducts($input: ProductSearchInput) {
products(input: $input) {
page
itemsFound
pages
items {
... on Cluster {
clusterId
names {
value
}
class
slugs {
value
}
defaultProduct {
productId
sku
names(language: "NL") {
value
}
price(input: { taxZone: "NL" }) {
gross
net
}
}
}
... on Product {
class
productId
sku
slugs {
value
}
names(language: "NL") {
value
}
price(input: { taxZone: "NL" }) {
gross
net
}
}
}
}
}

Variables:

{
"input": {
"language": "NL",
"term": "panel",
"searchFields": [
{
"fieldNames": [
"NAME",
"SKU",
"DESCRIPTION",
"MANUFACTURER",
"MANUFACTURER_CODE"
],
"boost": 1
}
],
"sortInputs": [
{
"field": "LAST_MODIFIED_AT",
"order": "DESC"
}
],
"page": 1,
"offset": 24
}
}

Expected result:

{
"data": {
"products": {
"page": 1,
"itemsFound": 3,
"pages": 1,
"items": [
{
"class": "PRODUCT",
"productId": 30,
"sku": "EL-UPL01",
"slugs": [{ "value": "ultrapanel-led-panel-light" }],
"names": [{ "value": "UltraPanel LED Panel Light" }],
"price": { "gross": 89.99, "net": 108.89 }
},
{
"class": "PRODUCT",
"productId": 27,
"sku": "CL-LP01",
"slugs": [{ "value": "cosmopanel-led-light" }],
"names": [{ "value": "CosmoPanel LED Light" }],
"price": { "gross": 74.99, "net": 90.74 }
}
]
}
}
}

You can expand the searchFields list to include more fields like SHORT_DESCRIPTION, KEYWORDS, EAN_CODE and SUPPLIER_CODE depending on how broad you want the search to be.

Explore the full schema

These are simplified versions of what a production frontend typically queries. The GraphQL API offers many more fields and query options:

What's next

Continue to Create an order to build a checkout flow.