The default behavior of a logic app is to sequentially execute action upon action when the preceding execution succeeded. When one action fails, the logic app execution is stopped and all remaining actions are never executed.
In some cases, this might be exactly the behavior we need, however in most cases, we would like to decide how to handle exceptions that occur during execution of the logic app flow.
This blog will describe how exceptions can be caught during runtime and how custom events can be implemented upon failed events. The topic is handled using a demo based on the validation of an XML-message.
As a use case to show how we can handle exceptions in Logic Apps, we’ll be using the “XML Validation”-connector. The connector allows you to validate documents against a pre-defined schema. In order to use such a schema within a Logic App, it needs to be added to an Azure Integration Account. For the demo, we’ll be using a very basic XSD:
Preparing the Integration Account
To create a new Integration Account, browse to the Azure Portal, click the “New”-button and search on “Integration Account”.
Continue by clicking the “Create”-button and providing details for the Integration Account.
Finish by clicking the “Create”-button.
We’ve chosen to use the “Free” pricing tier for our Integration Account, however there are some limitations when using this pricing tier.
- Only 1 free Integration Account per region
- Store a maximum of 10 agreements
- Store a maximum of 25 maps
- Unlimited number of schema’s, partners and certificates
For the purpose of the demo, we only need to upload 1 schema. Browse to your newly-created “Integration Account” & select the “Schemas”-tile
Press the “Add”-button and browse your computer for the xsd-file. By default, the name of your schema will be the same as the xsd-filename.
There are also some limitations when using schemas within an “Integration Account”.
- When larger than 2MB, the schema has to be uploaded to a File-store (e.g. Blob-container) and you need to provide the SAS-URI to the schema stored in your file-container.
- Even when using a File-store, the schema cannot be larger than 8MB
Designing the logic app
Go to the Azure Portal and create a new Logic App by clicking “New” and searching on “Logic App”.
Provide the details for your Logic App. Since we’ll be using an Integration Account, the Logic App needs to be created in the same region as the Integration Account.
After creation of the Logic App, we need to link the newly created app to our previously created Integration Account. Open the Logic App and click on “Integration Account” in the settings menu of the logic app.
Select your Integration Account from the drop-down menu and save the changes. If your Logic App and Integration Account are not in the same Region, the Integration Account will not appear in the drop-down.
Now we’ve completed the necessary configurations for our Logic App, we can start designing the flow. The general look of our sample Logic App is as follows:
- Logic app is triggered by an inbound HTTP POST request
- “XML Validation”-action is executed using the “ExceptionTester”-schema which we added to the Integration Account. As “Content” for the action, we cast the JSON-body from the trigger to XML using the @xml()-function
- Use a “Switch Case” to examine the result of the “XML Validation”-action. We use the ‘Code’-property from the xml validation action as our switch statement. Syntax: @actions(‘XML_Validation’)[‘Code’]
The value of the ‘Code’-property is equal to “OK”, indicating that the XML Validation succeeded. We will return an HTTP Response with Status Code 200 and a hard-coded response body.
The value of the ‘Code’-property is equal to “ValidationFailed”. The “XML Validation” executed, however validation failed because the message is not conforming to the XML schema.
Because the “XML Validation” executed, there is an output-object from the action which can be used to retrieve the error details. The errors are returned as an array, which we are re-using when sending our HTTP 400 response.
The value of the ‘Code’-property is equal to “BadRequest”. The “XML Validation” is never executed, in our case because the input for the @xml()-function could not cast the inbound JSON-body to an XML-message.
Because the “XML Validation” never executed, there is no output-object from the action. There is however an “error”-property on the action which we can use to retrieve the error details. We return a HTTP response with Status Code 500 and the error code and message -properties from the action.
The Logic App designer does not allow to change the values for the “runAfter”-property of an action. By default, this property is set to “Success”, enabling your new action only to be executed after a successful execution of its preceding action.
In our case, we would like to execute the “Switch Case” on both “Success” and “Failed” results of the “XML Validation”-action. To ensure this behavior, we need to alter the logic app in the Code View.
Update May 2017
In May 2017 some new changes where released on Azure Logic Apps. One of those updates allows us to specify the “Run After”-conditions from within the Logic App Designer. To specify the “Run After”-conditions, click the 3 dots in the “Switch”-action followed by “Configure run after”.
This will open the following window, where we can specify on which results of the previous action, the “Switch”-action should be executed.
Testing the scenarios
We will test 3 scenarios to display how successes or exceptions can be handled using logic apps. We’ll be using postman to trigger the HttpRequest-trigger in our Logic App.
Scenario 1: XML Validation execution succeeds
We will send a valid JSON object to the Logic App trigger endpoint. Our request body has valid values for each data type of the XML-schema.
Remember from the Logic App break down that the input for the “XML Validation”-action uses the xml()-function on the inbound JSON. In order to properly execute the xml()-function, we need to specify the Content-Type header as “application/json”.
We can see from the result that we receive a HTTP Status 200 OK and our hard-coded message body. When going through the run-details of this request, we can see the XML-Validation succeeded and the Case “OK” was executed within or switch.
If we look at the raw input details of our “XML Validation”-action, we can also see that the inbound JSON was successfully converted to an XML-message.
Scenario 2: XML Validation execution fails
Since we’ve defined the element “DecimalValue” as an “xs:decimal”-datatype and the “DateTimeValue”-element as a “xs:DateTime”-datatype in our ExceptionTester XML schema, we can easily cause the XML Validation to fail by providing incorrect values. Again, remember to set the Content-Type header on the request to make sure the @xml() function can be executed.
We can see from the result that we receive a HTTP Status 400 Bad Request. The body of our response contains an “Errors”-array with the actual error messages from the “XML Validation”-action. As expected, validation failed for both the “DecimalValue” & “DateTimeValue” elements.
When looking at the Logic App run-log, first thing we see is that the Logic App completed with a “Success”-state, due to the fact that we catched the exception from the XML Validation and made sure to reply with a proper HTTP response.
When we look at the run-details of this particular instance, we can see that the ”XML Validation”-action failed, but the “Switch Case”-action was executed anyway, because we have enabled it to run after a “Failed”-event on the XML Validation.
If we look at the details of the “XML Validation”-action, there are a couple of properties we can use to find out why the action failed.
We can see that the action has a status “Failed”, as well as an input link & output link.
The input link provides us more details about the message which was used to trigger the “XML Validation”-action. In our case, the input contains our XML-message as content as well as instructions on which schema to use during validation.
The output link gives us a view on the output which was generated by the “XML Validation”-action. In our case, the output is an array of “errors”, with some details about the actual validation exceptions. These are the same details which we used to construct our HTTP-response.
Scenario 3: XML Validation could not execute
Remember from previous steps, where we needed to provide the “Content-Type”-header when performing the HTTP request to trigger our logic app. This is required because the @xml() function can be used to either cast a string containing a XML or a JSON-string to XML. When not specifying the Content-Type, the @xml() function will try to convert a XML-string to a XML-document. In our case, this will cause an error, as our body does not contain a valid XML-document.
To trigger the logic app runtime failure, we will remove the Content-Type from our HTTP-request and keep the same body which we used during scenario 2.
We can see from the result that we receive a HTTP Status 500 Internal Server Error, which is what we wanted to return from our Logic App in case the “XML Validation”-action could not be executed. The error states that the input of the @xml function cannot be converted to XML.
When we look at the details of the run, again we can see that the logic app completed successfully.
When we look at the run-details of this particular instance, we can see that the ”XML Validation”-action failed, and again the “Switch Case”-action was executed, because we have enabled it to run after a “Failed”-event on the XML Validation. The major difference with this exception and with the exception from scenario 2 is the fact that in the previous scenario, the action could execute and would provide us with input and output information.
In this scenario, the input we provided made that the action could never execute. When looking at the run details of this scenario, there are some differences in how the exception was throws.
First thing we notice is the “InvalidTemplate”-exception on the XML Validation action. The “Status”-property has again a “Failed”-status, however we do not have any input or output links for the action. This is due to the fact that the “XML Validation”-action was never able to execute.
We do have a new property “Error” on the “XML_Validation” run details, which contains details about the failure. This is the same message which we’ve used in our HTTP-response.
Implementing exception handling in your logic app allows you to create logical steps which should only occur during failed events within the logic app and allows you to add custom error handling throughout the full run of your logic app. It enables you to implement custom logging frameworks or call event hubs for monitoring purposes outside of the default Azure Portal capabilities.
In our scenario, it makes perfect sense to catch exceptions and provide a more meaning-full HTTP-response to our client rather than having our Logic App run go into failure and have the standard Azure-error sent back to the client application. As with everything concerning Azure, it just comes down to deciding what the best option is for your logic app during design time.