Using the Azure Logic Apps Workflow Definition Language in Microsoft Flow .

(27/5/2017: blog post updated with a fifth example !

There are many situations with Microsoft Flow where we need non standard features, and as developer  I am way too often tempted to jump on the custom api and to create my custom Azure function or Azure Web API to provide exactly what I need. If all you have is a hammer everything will look like a nail…

Using the hammer can be overkilled so let’s add another tool to our (Flow) toolbox.

In some cases using the Azure Logic Apps Workflow Definition Language (WDL) directly  can be convenient. This WDL is actually part of Logic Apps, the workflow engine running behind Microsoft Flow.

This WDL is used behind any Flow and it shows-up in the Flow Designer.

Let’s take 5 examples

Example 1  (the easy one)

I have a SharePoint list with a column “Amount”. The flow is triggered when a new item is added into the list and I want to check its value. This is straightforward in Flow

flowcondition1

If we click the “option “Edit in advanced mode” we will see the Logic Apps WDL expression.

flowcondition2

To find more information regarding the Logic Apps WDL, go to the following site :

wdl

A flow is composed of a set of JSON objects and the associated value pairs are available from the WDL.

Example 2

A Flow is triggered when a new item is added in a SharePoint list. The SharePoint list has a “ID” system column which is unique. Each row is a contract and the contract ID must be unique. The contractID is automatically generated when the item is added in the list. The logic is : CONTRACT-XXXX where XXXX is the list idem ID minus 10 and formatted on 4 letters.

ex if ID is 50, the contract ID must be CONTRACT-0040.

To generate the contract, we need to rely on the Compose action.

The workflow will look like this :

flowcontract

The second action is the Compose action with the following value :

compose

compose2

“@concat(‘CONTRACT-‘,substring(string(add(sub(float(triggerbody()?[‘ID’]),10),10000)),1,4))”

if the SharePoint ID is 51

  • ?[‘ID’])  will return 51  (as a string) ; triggerBody returns the JSON object containing the trigger action.
  • float(triggerbody()?[‘ID’]) will return 51 (as a float)
  • sub(float(triggerbody()?[‘ID’]),10)  will remove 10 from 51-> 41
  • add(sub(float(triggerbody()?[‘ID’]),10),10000)  will add 10000 ->10041
  • substring(string(add(sub(float(triggerbody()?[‘ID’]),10),10000)),1,4) ->0041

In order to dig a little bit I’ve checked the content of triggerbody() by adding a Compose action (by the way don’t forget the double quotes before and after the expression)

triggerbodyInternal

What we get is this (a nice JSON result) :

returntriggerbodyInternal

I also noticed after running the flow, that my custom code became a Body variable (the body variable was not available before). :

bodyvariable

For the record  trigger-body() is a shorcut for trigger().outputs.body

Example 3.  

Let’s take a look at the Flow template

blopost10daystemplate

The logic of this template is that if the last blog post has been posted more than days days ago you will get a reminder. Here the condition must be expressed in WDL : (the basic mode doesn’t work at all)

bogpost10days

The WDL code is the following:

@less(string(first(body(‘List_all_RSS_feed_items’))[‘publishDate’]), addDays(utcnow(),-10))

body(‘List_all_RSS_feed_items’) : returns the raw content of what the action List all RSS feed items returns.

If we open a blog feed in a browser, for instance my blog feed https://sergeluca.wordpress.com/feed/

we will see that the publication date is a field named pubdate

However when we run the worklfow and check the value associated with a completed instance, we see this :

bodyblogshistory

Event tough the RSS is xml based, the RSS action has transformed it into JSON and the “Pubdate”  field has been renamed “PublishDate”

bodyblogs

So string(first(body(‘List_all_RSS_feed_items’))[‘publishDate’])  returns the publishing date of the first post (which is chronologically the last one)

@less(string(first(body(‘List_all_RSS_feed_items’))[‘publishDate’]), addDays(utcnow(),-10)) says if the last blog post has been published before today minus 10 days then a reminder needs to be sent.

So the rule is:

  • if you want to analyse an action output, use body()
  • if you want to analyse an trigger output, use trigger_body()  

Don’t forget to add the WDL site to you favorites.

Example 4. You want to check if a query to a SharePoint list is empty

The key thing is that  the list of all the items returned from Get item is stored in a vriable called ‘value’

-> if you switch the Condition action in “advacned” mode, you can type the expression:  “@empty(body(‘Get items’)[‘value’])

emptysharepointlist

another option would be:  @equals(length(body(‘Get Items’)?[‘value’]),0)

New Update (27/5/2017) : example 5

Example 5.

In one of my Flow I need to retrieve the current weather in a specific location. I’ve created a custom connector that retrieve the weather from the (free) REST service api.apixu.com. The connector is based on the following swagger file.

Basically I have a list of cities in a SharePoint list and when I add a new city in the SharePoint list a workflow start and display the current weather (temperature and weather picture).

weatherflow

The problem is the weather icon is not supported in the SharePoint picture url. My column is based on the “hyperlink or picture”  SharePoint type with the option “display as picture”.

The picture url returned by the web service is the following “//cdn.apixu.com/weather/64×64/day/113.png” this doesn’t work in SharePoint. If have to replace the “//cdn” with “http”, which is quite easy in WDL :

@replace(<the weather url> ,’//’,’http://&#8217;)

if you analyse the Swagger file, you will see the following schema:

          “schema”: {
              “type”: “object”,
              “properties”: {
                “current”: {
                  “type”: “object”,
                  “properties”: {
                    “temp_c”: {
                      “type”: “string”,
                      “description”: “Current temperature in celcius”,
                      “title”: “Current temperature in celcius”
                    },
                    “temp_f”: {
                      “type”: “string”,
                      “description”: “Current temperature in farenheit”,
                      “title”: “Current temperature in farenheit”
                    },
                    “condition”: {
                      “type”: “object”,
                      “properties”: {
                        “text”: {
                          “type”: “string”,
                          “description”: “Weather conditions”,
                          “title”: “Weather conditions”
                        },
                        “icon”: {
                          “type”: “string”,
                          “description”: “Weather condition icon url”,
                          “title”: “Weather condition icon url”
                        }
                      }
                    }
                  }

 

So the Flow looks like this:

I use an intermediate Compose action to store the weather url and I store the updated url in Compose 2 :

weatherflow1

 

Let’s see what happens at runtime :

weatherflow2

Have fun !

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s