# RulesEspresso - A Simple Rules Engine for OutSystems Developer Cloud

**RulesEspresso** is one of the components I published on **OutSystems Developer Cloud Forge**. It is a simple yet powerful rules engine that lets you define and execute business rules at runtime. While this approach isn't suitable for every use case, it offers several advantages over embedding business rules directly in the application code. The biggest benefit is that you can change business rules without redeploying the application, unlike logic built in **ODC Studio**. You can even let an application user create or modify business rules.

Let's consider the following scenario.

You are asked to implement a simple product discount. You need to create a discount scale that offers a discount based on membership status.

* Bronze status members receive 2%
    
* Silver status members receive 5%
    
* Gold status members receive 10%
    

Such a discount calculation can easily be implemented in ODC with an entity containing the discounts for each membership level. However, these discount calculations can change quickly over time, and changes could include:

* Discounts should not be applied if the product is already discounted.
    
* A discount should only be applied if the product's value exceeds a certain amount.
    
* A discount should only be applied if at least three items of the product are purchased.
    
* or a combination of the above……
    

Besides these permanent or semi-permanent changes, you might also encounter temporary changes, like additional discounts during a specific timeframe or even a complete change in the discount calculation if the company updates their membership program.

In short, implementing business rules directly within an application can become a burden and you may even risk losing money if you can't adapt to changes quickly enough. Externalizing business rules is the solution, as it allows you to define and modify business rules at runtime without changing server actions and redeploying the application.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Of course, even with the most advanced external rules definition, there is always a chance that you will still need to adjust the code. Business rules engines <strong>simply reduce the risk</strong> of needing to change the code.</div>
</div>

# **Demo Application**

This article features a demo application called "**RulesEspresso Demo**," available on **ODC Forge**.

* In the ODC Portal, navigate to **Forge - All Assets**.
    
* Search for "**RulesEspresso Demo**".
    
* Click on **Install**.
    

This demo relies on:

* **RulesEspresso** - This external logic library is the rules engine implementation you can use in your own applications.
    

# RulesEspresso Introduction

RulesEspresso is a **simple** implementation of a business rules engine. At a glance it allows you to

* Provide a flat property **JSON document** containing data as the **rules evaluation context**.
    
* Include an optional **JSON Schema** for data validation.
    
* Define one or more rules using **C# expressions** to evaluate data conditions, returning either true or false.
    
* Optional **result C# expressions** for each rule to add **calculated properties to the rules evaluation context** if the rule expression evaluates to true.
    

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">While this approach is suitable for many use-case scenarios, it has its limitations. In more complex situations, you might want to consider integrating with a mature business rules products (BRMS) like <a target="_self" rel="noopener noreferrer nofollow" href="https://www.ibm.com/products/operational-decision-manager" style="pointer-events: none">IBM Operational Decision Manager</a> or <a target="_self" rel="noopener noreferrer nofollow" href="https://docs.redhat.com/en/documentation/red_hat_decision_manager" style="pointer-events: none">Redhat Decision Manager</a>.</div>
</div>

## Parameters

RulesEspresso external logic library contains a single action **EvaluateRules** with the following input parameters

**dataObject**

This parameter accepts a JSON document with key/value pairs that can be used in rule definitions. It serves as the context for a single run of **EvaluateRules**. To generate the **dataObject** input, you can:

* Create a structure with attributes.
    
* Use the structure as a local variable in a server action flow and assign values to it.
    
* Serialize the variable using the **JSON Serialize** action - with **Serialize Default Values** set to **Yes**!.
    
* Use the serialized result as the value for the **dataObject** input parameter.
    

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">At the time of writing, RulesEspresso only supports flat JSON documents, which means you cannot use nested objects or arrays.</div>
</div>

**ruleDefinitions**

This parameter accepts a list of individual rules. Each rule consists of:

* **RuleName** - Any text. Each rule is evaluated separately, and you can use the rule name to identify it in the result of the Evaluate Rules action.
    
* **EvaluationExpression** - A boolean C# expression. This is where you specify a condition for the rule evaluation. Attributes of the dataObject are referred to by their names, and you can use C# methods within the conditions, such as DateTime.Now.
    
* **ResultExpression** - An optional C# expression that is evaluated if the EvaluationExpression is true. The ResultExpression can return a static or computed value, adding to the rules evaluation context, allowing you to use the value in subsequent rules.
    
* **ResultPropertyName** - Required if ResultExpression is set. This is the property name under which the result of ResultExpression should be added to the rules evaluation context.
    

**jsonSchema**

Takes an optional JSON schema to validate the dataObject. This validation is done only once, applying only to the input parameter and not to any ResultExpression values added during rules evaluation. The JSON schema is an excellent way to ensure that all necessary input parameters for rules evaluation are provided and have the correct values.

## Example

Let us do an example. We want to pass the total value of a purchase busket, along with a membership status and calculate a discount based on that:

* Bronze status members receive 2%
    
* Silver status members receive 5%
    
* Gold status members receive 10%
    

Our **dataObject** parameter looks like this

```json
{
  "totalValue": 7450.00,
  "memberStatus": "Silver"
}
```

The **ruleDefinitions**

Rule 1:

* **RuleName**: IsBronze
    
* **EvaluationExpression**: memberStatus == “Bronze”
    
* **ResultExpression**: totalValue \* 2 / 100
    
* **ResultPropertyName**: discount
    

Rule 2:

* **RuleName**: IsSilver
    
* **EvaluationExpression**: memberStatus == “Silver”
    
* **ResultExpression**: totalValue \* 5 / 100
    
* **ResultPropertyName**: discount
    

Rule 3:

* **RuleName**: IsGold
    
* **EvaluationExpression**: memberStatus == “Gold”
    
* **ResultExpression**: totalValue \* 10 / 100
    
* **ResultPropertyName**: discount
    

These rules evaluate the value of memberStatus and calculate the discount.

Finally, we are adding a **jsonSchema** to ensure that memberStatus is either Bronze, Silver, or Gold, and that totalValue is greater than 0.

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "totalValue": {
      "type": "number",
      "exclusiveMinimum": 0
    },
    "memberStatus": {
      "type": "string",
      "enum": ["Bronze", "Silver", "Gold"]
    }
  },
  "required": ["totalValue", "memberStatus"],
  "additionalProperties": false
}
```

You can try it out in the demo application and the Last Evaluation Result should look like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1750141311713/22e26841-31d6-413d-a447-879ae416642e.png align="center")

Change the values and add some extra rule expressions.

## Result

After evaluation, the results are returned in the **ValidationResult** output parameter:

* **IsValid** - This boolean value is true if all rules evaluated to true.
    
* **Document** - Contains the rules evaluation context JSON document, including all added result properties.
    
* **RuleResults** - An array of individual rule results. There is one entry for each rule evaluated, with the RuleName and a boolean IsValid property indicating whether the rule evaluated to true. You can use these individual entries to selectively take action within an action flow based on the result of a rule.
    

# Summary

This article introduces the **RulesEspresso** external logic library for OutSystems Developer Cloud. **RulesEspresso** is a simple rules engine that lets you externalize business rules instead of hard-coding them into OutSystems applications. While it handles many use cases, for more complex scenarios, you might want to consider a Business Rules Management Solution. These solutions offer many extra features, including custom code integration and enterprise-level business rules evaluation, unlike **RulesEspresso**, which is designed for application-centric rules evaluation.

I hope you enjoyed it and would appreciate your feedback.

%%[follow-linkedin-button]
