Understanding Bundle Configuration
Learn how bundle configuration works in Elastic Path, understand the data structures, and implement validation. For a practical implementation guide, see Configure Dynamic Bundles.
Configuration Structure
Bundle configuration defines which component options are selected and their quantities:
interface BundleConfiguration {
selected_options: {
[componentKey: string]: {
[optionId: string]: number; // Quantity
};
};
}
// Example configuration
const configuration: BundleConfiguration = {
selected_options: {
"processor": {
"prod-i9-uuid": 1
},
"graphics_card": {
"prod-rtx4080-uuid": 1
},
"storage": {
"prod-ssd-2tb-uuid": 2 // quantity of 2
},
"accessories": {
"prod-mouse-uuid": 1,
"prod-keyboard-uuid": 1
}
}
};
Key Concepts
Component Keys
- Unique identifiers for each bundle component
- Match the keys in
bundle.attributes.components
- Used as top-level properties in configuration
Option IDs
- Product IDs that can be selected for each component
- Must match available options in component definition
- Used as keys within component configuration
Quantities
- Number of each option selected
- Must respect min/max constraints
- Always stored as numbers
Validation
Validate configuration before API calls:
function validateConfiguration(
components: Components,
configuration: BundleConfiguration["selected_options"]
): { isValid: boolean; errors: string[] } {
const errors: string[] = [];
// Check each component's requirements
Object.entries(components).forEach(([componentKey, component]) => {
const selectedOptions = configuration[componentKey] || {};
const totalQuantity = Object.values(selectedOptions)
.reduce((sum, qty) => sum + Number(qty), 0);
// Validate minimum requirement
if (component.min && totalQuantity < component.min) {
errors.push(
`${component.name}: Select at least ${component.min} option(s)`
);
}
// Validate maximum requirement
if (component.max && totalQuantity > component.max) {
errors.push(
`${component.name}: Select at most ${component.max} option(s)`
);
}
});
return {
isValid: errors.length === 0,
errors
};
}
Configuration Persistence
Save configurations to improve user experience:
// Save to URL for sharing
function saveConfigurationToUrl(
bundleId: string,
configuration: BundleConfiguration["selected_options"]
) {
const configString = btoa(JSON.stringify(configuration));
const params = new URLSearchParams(window.location.search);
params.set('config', configString);
window.history.replaceState(
{},
'',
`${window.location.pathname}?${params.toString()}`
);
}
// Restore from URL
function restoreConfigurationFromUrl(): BundleConfiguration["selected_options"] | null {
const params = new URLSearchParams(window.location.search);
const configString = params.get('config');
if (!configString) return null;
try {
return JSON.parse(atob(configString));
} catch (error) {
console.warn('Invalid configuration in URL');
return null;
}
}
// Save to localStorage
function saveConfigurationToStorage(
bundleId: string,
configuration: BundleConfiguration["selected_options"]
) {
const key = `bundle_config_${bundleId}`;
localStorage.setItem(key, JSON.stringify({
configuration,
timestamp: Date.now()
}));
}
Using Configuration with SDK
Apply configuration when adding to cart:
// Configure bundle and get pricing
const configResponse = await configureByContextProduct({
path: { product_id: bundleId },
body: {
data: {
selected_options: configuration.selected_options
}
}
});
// Add to cart with configuration
await manageCarts({
path: { cartID: cartId },
body: {
data: {
type: 'cart_item',
id: bundleId,
quantity: 1,
bundle_configuration: configResponse.data?.meta?.bundle_configuration
}
}
});
Best Practices
- Always validate configuration before API calls
- Handle number types correctly for quantities
- Provide clear error messages for invalid configurations
- Consider persistence for better user experience
- Clean up stale data from storage periodically
Common Pitfalls
- Not validating option IDs exist in component definition
- Storing quantities as strings instead of numbers
- Forgetting to check min/max constraints
- Losing configuration on page refresh
- Not handling invalid saved configurations gracefully
Next Steps
Now that you understand bundle configuration:
- Configure Dynamic Bundles - Build a complete bundle configurator UI
- Bundle Pricing Strategies - Handle dynamic pricing
- Add Bundle to Cart - Complete cart operations