Welcome to the second part of this series of blog posts on How to throw custom exceptions inside Logic Apps. In this series of five blogs, I will cover throwing custom exceptions in Logic Apps. I will cover the following topics:
- Part I – Using default capabilities
- Part II (this article) – Using default capabilities – Extract failure information
- Part III – Using default capabilities – Avoiding too many condition actions
- Part IV – Using a child Logic App to throw a custom exception
- Part V – Using an API Management Throw Exception API
In this second approach, we are going to do a small fine-tuning of the previous approach by adding the capability to define custom error messages for each condition and, of course, get that information inside the Catch Scope.
Throw exceptions inside Logic Apps with failure information: Using a Variable and Expression
For that, we need to:
- Expand the Try Scope, expand the Check if name is John condition, and on the False branch:
- Click on Add an action.
- On the Choose an operation window, search for Variable and then select the Set variable.
- On the Set variable action, set the following configurations:
- On the Name property, select the variable that is created at the beginning of this workflow, in my case varResultMessage.
- On the Value property, from the Dynamic content window, select the token name and type the following string is an Invalid Name!
- Move the Set variable action to on top of the throw exception
- Expand the Try Scope, expand the Check if Age is Less than 18 condition, and on the False branch:
- Click on Add an action.
- On the Choose an operation window, search for Variable and then select the Set variable.
- On the Set variable action, set the following configurations:
- On the Name property, select the variable that is created at the beginning of this workflow, in my case varResultMessage.
- On the Value property, type the following string Invalid Age! You need to be older than 18.
- Move the Set variable action to on top of the throw exception action.
Now that we have configured each condition to define the proper error message let’s go deeper into the Catch Exceptions. In real case scenarios, not only do we need to handle these custom exceptions that we could raise from within our business logic, but we also need to control and get other types of errors like calling an external service or executing expressions inside our workflow.
You can read more about how to catch the proper error message in one of these blog posts:
- How to get the Error Message with Logic App Try-Catch (Part I)
- How to get the Error Message with Logic App Try-Catch (Part II) – Using an Azure Function
- How to get the Error Message with Logic App Try-Catch (Part III) – Using a generic Logic App
Or you can get a fully detailed whitepaper about this topic with more information: Logic Apps Consumption – How to get the Logic App error detail message guide.
To simplify this paper, we are going to use the Azure Function approach (Part II) in our exercises. To do that, we need to:
- Expand the Catch Scope and delete the existing Set variable.
- Click on Add an action.
- On the Choose an operation window, search for Azure Functions and then select the LAErrorExtract (you may have a different name) function app.
- Then select the ExtractLogicAppError action.
- On the Set variable action, set the following configurations:
- On the Request Body property, set the following code:
{ "SubscriptionId":"xxxxxx", "logicAppName":"@{workflow()['run']['name']}", "resourceGroup":"RG-IT-EAI-POC", "rundId: "@{workflow()['run']['name']}" }
- On the Catch Scope, click on Add an action.
- On the Choose an operation window, search for Variable and then select the Set variable action.
- On the Name property, select the variable that is created at the beginning of this workflow, in my case varResultMessage.
- On the Value property, type the following expression:
- body(‘ExtractLogicAppError’)[0][‘errorMessage’]
Now, if we test this second approach with a valid message, we will still receive the same expected outcome:
{ "Result": "Application accepted!" }
However, if we try with an invalid age or name, then we will receive the following error message:
{ "Result": "Unable to process template language expressions in action 'Throw_Age_exception_using_variable_and_expression_' inputs at line '0' and column '0': 'The template language function 'int' was invoked with a parameter that is not valid. The value cannot be converted to the target type.'." }
And that’s not exactly what we wanted and were expecting. The reason why is that this is the generic code we added to our Catch Scope.
Indeed, in this approach, we are not throwing a custom exception but, in reality, forcing the Logic App engine to throw an exception based on a failure that we are inducing in our logic. Next, the catch scope gets the correct error information. To solve this “problem” in this approach, we need to:
- On the Catch Scope, click on Add an action.
- On the Choose an operation window, search for Control and then select the Condition action.
- On the Condition action, add the following condition:\
- varResultMessage is equal to “Application accepted!”
- Move the two existing actions inside the True
The default value of the varResultMessage is “Application accepted!” and every time there is a situation we want to raise an exception, we first set a new value to this variable setting the correct error description. But if we have more logic in our workflow, we also need to be aware that a failure can happen there, and we need to get that error message. So, in this case, we will be checking if the varErrorMessage is the default value that we need to query the REST API in order to get the error message; otherwise, we will use the one we define.
Now, if we try our solution again, we will get our custom error description.
{ "Result": "Invalid Age! You need to be older than 18." }
One of the most important advantages of this solution is:
- To have a good error description of our custom exceptions.
- It is a solution that is simple to implement.
However, there are some drawbacks also:
- In order to implement this approach, we actually have to add to our business logic 6 unnecessary actions (or that can be avoided), and this is a simple scenario.
- Two variables’ initialization.
- For each custom exception, we need to set up the variable with the custom error description and set up a variable to force a failure to happen.
- We are not throwing a custom exception. Instead, we are forcing an error to happen.
- Add more complex logic to the catch scope.
- It is not a global solution, so for each Logic App, we always need to implement this logic.
I can probably say that this solution is good for small business Logic, small solutions, or for clients that have a small footprint in Azure.
Approach 2: Small fine-tuning
I like to optimize my solution to the max. Also, be aware that in the Logic App solution, we pay per action. So, if we can reduce the number of actions, it will be better.
In this case, let’s remove the varSupportForceError variable. To do that, we need to:
- On our Logic App, click on … (3 dots) and then select the option Delete.
- Because we delete this variable, we need to fix the Throw action in each condition inside the Try Scope.
- Expand the Check if name is John condition, and on the false branch, delete the action Throw Name exception using variable and expression.
- Expand the Check if Age is Less than 18 condition, and on the false branch, delete the action Throw Age exception using variable and expression.
- Now, back to the Check if name is John condition, and on the false branch, click on Add an action. On the Choose an operation window, search for Data Operation and then select the Compose action.
- On the Compose action, set the following configuration:
- On the Inputs property, add the following expression: int(‘__ERROR__’).
- Now, we need to do the same in the false branch of the Check if Age is Less than 18
Now if we try to test our solution, we will end up with the same result:
{ "Result": "Invalid Age! You need to be older than 18." }
But in this solution, we have one action less.
I hope you enjoy and stay tuned for part III.