Fluent Commerce Logo
Docs

Utility Bundles Overview

Essential knowledge

Authors:

Kirill Gaiduk, Ben Harrison, Holger Lierse

Changed on:

15 Aug 2025

Overview

The Fluent Commerce Utility Bundles are a set of libraries designed to accelerate Rule development, reduce boilerplate code, and improve the overall quality and maintainability of implementations. They are the cornerstone of writing maintainable, reusable, and easily upgradeable Rules for the Fluent Commerce platform.

Key points

  • Prerequisites: You should have knowledge of the Rules SDK, including Designing Rules, Rule Structure, Writing Rules, Rule Development Guidelines, General Principles, and Rules SDK - Getting Started.
  • Focus on Business Logic: The libraries handle common, repetitive tasks (like data fetching and JSON conversion), allowing developers to concentrate on writing the business logic that delivers value.
  • Three Specialized Bundles: The utilities are organized into three modules: `util-core` for essential daily tasks, `util-dynamic` for building runtime queries, and `util-test` for simplifying testing.
  • Easy Upgrades: Receive bug fixes and new features from Fluent Commerce by updating the dependency version in your `pom.xml`, ensuring your implementation stays current.
  • Built for Extensibility: The utilities are designed to be flexible, allowing you to inject your custom logic into standard processes.

The Design Philosophy: From Source Code to Building Blocks

Historically, customizing Rules often required developers to modify the rule's source code directly. While this offered flexibility, it made upgrades difficult. A bug fix or performance improvement from Fluent Commerce would require a manual, time-consuming code merge.The Utility Bundles represent a shift in this approach. Instead of providing complex Rule source code, Fluent Commerce now provides a set of powerful, reusable building blocks. The core logic for common tasks is extracted into these utility libraries.This has two major benefits:
  • Simpler Rules: Your Rules become much cleaner and more focused on the business logic, as the overhead of data fetching, transformation, and action creation is handled by the utilities.
  • Effortless Upgrades: You can receive new features, bug fixes, and performance improvements by updating the utility dependency version in your `pom.xml`. No more manual merging.

Breaking Down a Rule: How Utilities Help

Most Rules follow a similar structure. The utility libraries provide helpers for each step of the process, designed with specific principles in mind.

1. Validation

Utilities help check that inputs are correct, so the Rule can exit early if there's nothing to do. The key principle is understanding what to validate and when:
  • Rule Properties: These don't change at runtime, so their validation should be handled by workflow unit tests, not runtime checks. The `RuleUtils` utility helps retrieve them safely.
  • Event Attributes: These do change at runtime, so they are excellent candidates for validation within a utility. For rich types, the best approach is to map the attribute directly to a POJO using `JsonUtils`.

2. Data Fetching

Utilities provide helpers for common data-fetching use cases. The goal is not just to expose raw data, but to provide data that is ready to be used.
  • Think Usage: For example, instead of a generic `getOrder(context)` method that would require every Rule to then filter out already fulfilled items, a better utility is `getUnfulfilledItems(context)`, which does that logic for you.

3. Business Logic

This is where your unique logic lives. The utilities are designed to support this with a key principle in mind: extensibility.
  • Pass in Functions: A powerful pattern used in the utilities is allowing developers to pass in their own functions to override or extend default behavior. For example, a utility that finds the best fulfillment plan might accept a custom scoring function as a parameter. This makes the utilities flexible building blocks rather than rigid, black-box solutions.
  • Identify Archetypes: The utilities are often built to support common Rule "archetypes", such as "Flow Control" rules that conditionally send events, or domain-specific ones like "Fulfillment Strategy" rules.

4. Actions

Utilities help build and produce the outcome of the business logic, especially for complex actions like mutations.
  • Convert Logic to Actions: For example, if a business logic utility returns a list of proposed fulfillments, another utility can take that list and turn it into the required set of `updateFulfilment` mutations.

Why Use Utility Bundles?

  • Accelerate Development: Handle common tasks like date formatting, JSON conversion, and event forwarding with single lines of code.
  • Improve Code Quality: Leverage pre-built, tested functions that handle common error scenarios and edge cases.
  • Simplify Maintenance: Update a utility function in one place, and the change is reflected everywhere it's used.
  • Easy Upgrades: Stay current with the latest features and bug fixes from Fluent Commerce by updating the dependency version in your `pom.xml`.

The Utility Bundles

The utilities are organized into three distinct modules, each serving a specific purpose. Fluent Commerce will continue to release more utilities over time to cover more common order and inventory functionality.

Core Utilities

The foundational library containing essential helpers for everyday development tasks. If you are building rules on the Fluent Commerce platform, you will be using this bundle. It handles common tasks like event creation, setting retrieval, and JSON manipulation so you can focus on business logic.
  • Key Classes`EventUtils``SettingUtils``QueryUtils``RuleUtils``JsonUtils`.

Dynamic Utilities

This package offers utilities to generate GraphQL queries and mutations at runtime. This is crucial for scenarios where the data you need to fetch or update is not known until the Rule is executed, enabling more flexible and configurable Rule creation across different domains.
  • Key Classes`DynamicUtils`, an advanced `JsonUtils`.

Test Utilities

A dedicated toolkit for writing robust unit and integration tests. It provides mock executors, context generators, and other helpers to simplify and standardize the process of testing your Rules, saving you significant time and effort.
  • Key Classes`RuleExecutor``WorkflowExecutor``MockApiClient`.

A Practical Example: Tracking Status History

This example shows how utilities work together to implement a common requirement: tracking how long an entity spends in each status.
1@RuleInfo(name = "UpdateStatusHistory", /*...*/)
2public class UpdateStatusHistory implements Rule {
3
4    // A POJO to represent the entity fields we need
5    // With @Data, 'private' is redundant
6    @Data
7    public static class EntityData {
8        String createdOn;
9        String status;
10        List<Attribute> attributes;
11    }
12
13    @Override
14    public void run(Context context) {
15        // 1. DATA FETCHING: Use DynamicUtils to get only the fields we need
16        EntityData entity = DynamicUtils.query(context, EntityData.class);
17        
18        // Find the existing history attribute from the entity's attributes
19        // (Logic to find attribute by name is omitted for brevity)
20        Optional<Attribute> historyAttribute = findHistoryAttribute(entity.getAttributes());
21        
22        // 2. BUSINESS LOGIC: Deserialize old history, calculate time, add new entry
23        // The list of previous status updates is retrieved from the attribute using JsonUtils
24        List<StatusUpdate> history = getHistoryFromAttribute(historyAttribute);
25        long durationInPreviousStatus = calculateDuration(history, entity.getCreatedOn());
26        history.add(new StatusUpdate(entity.getStatus(), /*...*/));
27        
28        // 3. ACTIONS: Use DynamicUtils to persist the updated attribute list
29        Attribute updatedAttribute = createHistoryAttribute(history);
30        DynamicUtils.mutate(
31            context,
32            ImmutableMap.of("attributes", Collections.singletonList(updatedAttribute))
33        );
34    }
35}