In Azure Logic Apps workflows, you can implement conditions and switch cases to control the flow based on runtime inputs and outputs. This functionality is quite useful, and in many cases, can be used to implement the business rules required. However, those business rules are inherent to the workflow, and when business rules change often, they would end up being hard to maintain.
BizTalk Server, which is the on-premises integration platform from Microsoft, provides a Business Rules Engine that allows you to define, build, manage and maintain business rules in a way that the integration orchestrations can be abstracted from changes on the business rules. Unfortunately, at the time of writing, in Logic Apps there is not such a feature.
Recently, Microsoft have released the support of Liquid Templates to transform JSON and XML objects. These transformations are based on DotLiquid, the .NET Implementation of Liquid templates themes from Shopify.
If we wanted to externalise business rules from Logic Apps workflows, so that when they change we don’t need to update the workflow, we have two options:
- we could use Azure Functions and implement business rules as .NET code. NRules is an interesting open-source library for this, and now
- we could use Liquid Templates.
In this post, I’ll show how to implement business rules in Logic Apps using Liquid Templates.
Farm to Table, the fresh produce drone delivery company, want to implement some business rules to be applied when receiving orders. All the order processing is currently handled by Logic Apps. These business rules can change over time, and they want to be able to update them with the minimal effort (think of development, testing and deployment). They have two main business rules: 1) to define whether an order must be manually approved and 2) applying discounts based on promotions. Promotions rules change much more often than approval rules. Because these rules change often, they want to externalise them from the Logic App workflow.
They want to implement the following business rules:
- Manual Approval of Orders: Based on the current capacity of the drone fleet, orders with a total weight greater than 18 kg must be approved. Additionally, orders with a subtotal of less than $10 AUD require a manual approval as well.
- Discount: currently, there is a promotion for orders placed on the mobile app. Other channels don’t have a discount.
- All orders coming from the mobile app would get at least 5% discount.
- Orders with a subtotal of $50 AUD or more and with a total weight of less than 10 Kg would get higher discount of at least 7%. Additionally,
- Orders meeting the criteria above to be delivered to Zone 1 (Zip codes: 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008), get a 15% discount
- Orders meeting the criteria above to be delivered to Zone 2 (Zip codes: 3205, 3206, 3207), get a 10% discount.
As you can imagine, implementing these business rules as part of the Logic App workflow would add a lot of complexity, let alone the effort required when business rules, like promotions, change.
To implement these business rules, we will create a Liquid template, which will be abstracted from the Logic App workflow. This will allow us to update the business rules as required without impacting the workflow, thus we can reduce the time required for development, testing and deployment.
Orders received by Farm to Table follow the structure shown below
Business Rules as a Liquid Template (1st Iteration)
We will implement the business rules as a Liquid template. If you want to get familiar with Liquid templates, I would recommend to go to the official documentation. It’s worth noting that because Logic Apps implementation of Liquid is based on DotLiquid, not all the filters are supported or work exactly the same. For instance, filters are called with the first letter in uppercase, as opposed to lower case in the Ruby implementation. Additionally, you need to be familiar with the creation of Integration Accounts and adding Liquid templates to it as described here.
Below, there is the first iteration version of the business rules implementation in Liquid. As you can see, I’m creating two arrays of zip codes for the zone conditional. Everything else should be self-explanatory
This Liquid template, should output a response like the one shown below:
Having this response will allow us to use the requiresApproval boolean property, and the calculated discount later in the workflow, with all the business rules externalised from the workflow.
Business Rules as a Liquid Template (2nd Iteration)
As part of the requirements, Farm to Table, wants to be able to enable and disable discounts very easily. They also want to be able to easily change the channels to which discounts apply, zones, and thresholds for discount levels and approvals. To do that, we can refactor the Liquid template, so we can create a vocabulary with easy-to-maintain variables.
A sample of the refactored business rules is shown below
This template will create exactly the same output, but now it should be easier to maintain.
The Order processing Logic App workflow is instantiated by an HTTP call. Then we need to apply business rules to know the discount and whether the order must be manually approved. To do so, we will use the Transform JSON to JSON action to invoke the Liquid template with the business rules. We pass the order as the content parameter and the name of the Liquid template as the map. The Liquid template must be already in the Integration Account and the Integration account must be assigned to the Logic App workflow. Then the workflow will proceed with further processing, including the manual approval when required. A snapshot of the first part of the workflow is shown as follows.
Implementing a generic serverless Business Rules Engine
Now, we know how to call externalised business rules using Liquid templates within Logic Apps workflows.
However, you could even implement a serverless Business Rules Engine using these tools, to be used not only from Logic Apps but other apps. This could be handy when business rules change often, and you prefer not to implement them as part of the application code.
To do so, we could deploy all our business rules as Liquid templates in an Integration Account, and then create an Http triggered Logic App workflow, which receives as body the JSON document for which business rules are to be applied. Additionally, this Logic App will need to receive the name of the Liquid template to be invoked.
In my Logic App, I am accepting the name of the Liquid template as an Http header. I named the custom header as X-BusinessRulesName. I used this header value to dynamically invoke the corresponding Liquid template in a Transform JSON to JSON action. The Transform JSON to JSON action is called Apply Business Rules. This Logic App will return the output of the Business Rule as the response body.
The Logic App workflow is shown below, including the code behind the Apply Business Rules (Transform JSON to JSON) action.
This Http Logic App, together with business rules as Liquid templates, can be used as a Business Rules Engine. Quite handy, don't you think? :)
There are two considerations to be taken into account when using Liquid Templates
- Liquid Templates, particularly the DotLiquid implementation might not have all the Control Flow tags and Filters required for your business rules. So you need to know what the limitations are.
- Liquid Templates are to be stored in an Integration Account. As described here, you can use an included (free) Integration Account with no additional cost to host your Liquid Templates. However, this one does not provide an SLA . For production workloads, a Basic or Standard Integration Account is suggested, and there is a cost associated with it.
In this post, I’ve shown how to implement externalised business rules on Logic Apps using Liquid templates. Additionally, we’ve seen how we can implement a generic Business Rules Engine using this same approach and dynamically invoking a particular business rule Liquid template. I hope you’ve found this post handy. Feel free to add your comments or ask any questions below.
Cross-posted on Paco’s Blog.
Follow Paco on @pacodelacruz.