Custom connectors, taking Azure Logic and API apps for a spin - Part 2

A few weeks ago I wrote about Azure Logic apps, a sort of "BizTalk light in the cloud" promising easy integration using a visual drag and drop "connectors"-based approach. You can take a look at the first part here.

So what happens now?

We left Logic Apps after having successfully used standard connectors to create a logic app that would do the following.

  1. Run every minute
  2. Search for the latest tweets containing a given string (the URL of this blog)
  3. Send the first result as a text message

This was achieved using the "Recurrence", "Twitter" and "Twilio" connectors respectively. The problem with the logic app was that it runs every minute, and always send a text message, even though the most recent text message has not changed. That becomes tiresome really fast.

In this post we will try extending the logic app with a custom connector, a "tweet filter", that will ensure that we only send a text message if the most recent tweet has changed.

Custom connector basics

To get started we need to understand a few things about connectors. First of all, connectors are really just Azure API apps, which are really just Web API apps (with a few extra goodies). This is good news, because you probably already know everything needed to create one.

Load up Visual Studio and create a new web application of type "Azure API App".

Create new API app

What makes an Azure API app different?

There are a couple of things that set the Azure API app apart from a normal Web API. There is an extra ApiApps-library providing some extra Azure API app functionality, as well as a new apiapp.json project file. We won't delve into that now, but focus on a third thing that we need to know about if we want to understand API apps.

Swagger

The Azure API app comes with Swashbuckle installed, this enables your app to speak Swagger automatically providing discovery of the API, a UI to access it and documentation.

The self-describing capabilities are what Azure uses to make your API functionality available in the Logic App workflows later.

To enable Swagger you need to open up up /App_Start/SwaggerConfig.cs and uncomment these three lines.

})
.EnableSwaggerUi(c =>
{

Let's make the Tweet Filter API app

If you have created the application and enabled Swagger as detailed above you are ready to write some code. There are two different types of connectors we can create.

  1. Triggers
  2. Actions

Remember our example from Part 1? The trigger is the first "Recurrence"-connector in the workflow that will run (or trigger) the workflow every minute. Each of the subsequent connectors, Twitter and Twilio, are actions.

Tweet to Text Logic app

What we want to create in this case is a connector to put between the Twitter and Twilio connectors. Another action that is. The nice thing about actions are that they are just regular old Web API actions.

(Triggers are different, they come in both push and pull flavours, if you are interested in reading more about how to create triggers you should take a look at Azure App Service API app triggers from the Azure documentation.)

So in order to create our filter functionality, let's go ahead and create a new FilterController with a single "Filter"-action. Like so.

using System;
using System.Web.Http;

namespace TweetFilter.Controllers
{
    public class FilterController : ApiController
    {
        private readonly TweetFilter _filter;

        public FilterController()
        {
            _filter = TweetFilter.CreateTweetFilter();
        }

        [HttpPost]
        [Route("api/tweet")]
        public string Filter(string tweet) {
            return _filter.Filter(tweet);
        }
    }
}

The actual filtering is done by the "TweetFilter"-object. It basically keeps track of the last tweet it has seen, and if the new tweet is the same it returns an empty string instead of the tweet.

public class TweetFilter
{
    private static TweetFilter _filter;
    private string _lastTweet;

    private TweetFilter() { }

    public static TweetFilter CreateTweetFilter()
    {
        return _filter ?? (_filter = new TweetFilter());
    }

    public string Filter(string tweet)
    {
        if (_lastTweet != null && tweet.Equals(_lastTweet))
            return "";

        _lastTweet = tweet;
        return tweet;
    }
}

Deploy the API app

Now that we have our filter ready, all we need to do is deploy it to the same resource group that the logic app belongs to.

You can use the publish functionality directly from Visual Studio if you want. Note that since API apps are basically like any other web app you would run in Azure, it is no more or less difficult to deploy using whatever continuous delivery mechanism you are used to.

Deploying an API app

Add the API app to the Logic app workflow

When you open up your Logic app workflow in the Azure Portal the new API app should appear on the right side along with the other connectors you have installed in the resource group.

Available API apps

Let's go ahead and add the new app to our existing workflow.

Filtered logic app flow

Now, when we save and run this workflow, rather than passing the tweet directly to Twilio to send a text message, it will be passed to our filter. In reality this means the Logic app will just call our API action, and it will return either an empty string, or the actual tweet - if it is different from the last tweet it saw.

The result of our Filter-action is then passed to the Twilio connector. By now we have achieved what we wanted to because Twilio refuses to send a text message without content. When the Logic app runs it will work if there is a new tweet, but fail at the last step if nothing has changed since the last time it ran.

That is not very elegant though, and thankfully we can add a "condition" to the the Twilio-connector, telling it to only run if it receives something other than an empty string.

Azure Logic app conditions

The conditions are expressed through formulas that should allow us to do these checks easily. I didn't get it to work how I wanted though and I simply gave up (because at this stage I had spent too much time getting everything else to run), which brings me to my next point.

Is this something I will be using?

When I worked on the first part of this blog post, pretty much everything worked according to plan. The UI had a few hiccups, but nothing I didn't anticipate. I was able to get things running in a short amount of time, and it seemed to work.

After a few weeks when I came back to the Logic app to write the follow-up everything had stopped working. None of the connectors were running anymore (even though I was still being billed for having them provisioned).

Removing and re-provisioning the connectors caused trouble with the gateway. Fixing the gateway in turn seemed to cause problems with my custom connector. All in all I have spent maybe 15 min writing code for this blog post, and a few hours shouting at my monitor because I couldn't get things to work.

The overall impression I am left with is that the concept of Logic apps has some promise, but the implementation still needs more than a bit of polish.

I don't see myself using it for "serious business", and it will take a lot to make me change my mind about that, even if things eventually work smoothly. I understand the allure of easy integration, but these things are hard by nature, and it will take a lot of effort to get Logic apps to a point where I would trust them with any kind of important business operation.

But every business has secondary not-quite-as-essential use cases where something like Logic apps might be appropriate. I considered creating a small logic app to text me a few signup stats from my SaaS product, something I am interested in, but don't depend on.

I will consider doing that when Logic apps have had time to mature a bit. For now it would be much easier for me to just code it up and deploy it as a webjob. The same result, but with fewer tears.

View Comments