Creating connectors for your Logic Apps/Flow (Part 3 – More triggers) 03 May 2017 Michael-Van-Wesemael API Apps, Azure, Flow, Logic Apps So, let's recap: we had regular connectors, we had poll triggers. So, we're still missing the push triggers. A poll trigger needs to be polled regularly by the logic app to see if it can continue. A push trigger does not have to be polled, it will tell the logic app when it needs to continue, passing the necessary information. At this moment a push trigger needs to be called by a webhook-action. Your trigger needs two function : Subscribe and Unsubscribe. In the Webhook-action these functions will automatically be called when the Logic App starts or stops. The WebHook action needs to pass the callback-url to your Subscribe/Unsubscribe-action. This callback-url is the url your API app will call for starting the Logic App. Your functions should look like this : public static List subscriptions = new List();[HttpPost, Route("api/webhooktrigger/subscribe")]public HttpResponseMessage Subscribe([FromBody] string callbackUrl){ subscriptions.Add(callbackUrl); return Request.CreateResponse();}[HttpPost, Route("api/webhooktrigger/unsubscribe")]public HttpResponseMessage Unsubscribe([FromBody] string callbackUrl){ subscriptions.Remove(callbackUrl); return Request.CreateResponse();} .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } The idea is that you call back the logic apps using the list of subscriptions as this: using (HttpClient client = new HttpClient()){ foreach (string callbackUrl in subscriptions) await client.PostAsync(callbackUrl, @"{""trigger"":""fired""}", new JsonMediaTypeFormatter(), "application/json");} After this your Logic app continues. For using the pushtrigger you need a webhook-connector in your logic app. This needs to call the subscribe and unsubscribe-methods of your API App. For the body you need to pass the callback url. But still it won't work. When going to the Trigger History you can find that you get a failure because of an error with the content-Type. It is simple to solve: Show the advanced options of your webhook-connector and add the content-type to your subscribe- and unsubscribe-headers as this: Problem solved !
Creating connectors for your Logic Apps/Flow (Part 2 – Triggers) 07 March 2017 Michael-Van-Wesemael API Apps, Azure, Flow, Logic Apps In part 1, we saw how to add regular connectors for using in Azure Logic Apps. Remember: the purpose of these blog posts is just for pointing out some gaps in the documentation you'll find on the internet. Next to regular connectors, we can also create connectors to be used as connectors, i.e. connectors that can initiate the logic apps. There are two types of connectors : poll and push connectors. The difference in short is : Poll connectors will be regularly called to see if the logic app should start, using a polling mechanism. Push connectors will call the Logic app to start, using a webhook mechanism. Poll triggers As mentioned before: poll triggers will be polled on a regular interval to see if something is changed, starting the logic app when this is the case. So how is this polling working ? If you add your API app as first connector in your logic app, he'll show you your triggerfunctions. Just select your trigger, and specify a polling-interval.The triggerstate can be left blank, but will be used for keeping track of the last poll-time. What will happen now: The Logic App will poll your API app, by calling the Get-method. The triggerstate will initially be empty. The Trigger should return HTTP 202 Accepted. The triggerstate should also be returned, containing the time of calling. next polls will contain a value for the triggerstate. Here we can have two options: if we do not need to trigger (i.e. no need to start the Logic App), the App just needs to return HTTP 202 again, with no changes. If the Logic app now has to start, the app needs to return HTTP 200 OK, with a modified triggerstate, and with, of course, the information you would like to pass to the Logic App In my case, I want to trigger the logic app, when the weather changed. The information to pass looks like this : public class WeatherInfo { public int Temperature { get; set; } = 10; public string WeatherCondition { get; set; } = "Stormy"; public int ChanceOfPrecipitation { get; set; } = 80; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Again : on the get-function, make sure to specify what will be the output. Otherwise your output will not be usable/visible in the logic app. [SwaggerResponse(HttpStatusCode.Accepted)] [SwaggerResponse(HttpStatusCode.OK, "triggered", typeof(WeatherInfo))] [SwaggerOperation("CheckWeatherReport")] For being able to send back the information, ánd the triggerstate, I created a simple helperfunction. private HttpResponseMessage GenerateResponse( HttpStatusCode code, string triggerState, string retryAfter, WeatherInfo data = null) { HttpResponseMessage responseMessage = Request.CreateResponse(code, data); responseMessage.Headers.Add("location", $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}/api/weather?" + $"triggerState={HttpUtility.UrlEncode(triggerState)}"); responseMessage.Headers.Add("retry-after", retryAfter); return responseMessage; } After deploying the API app to AZure (don't forget the metadata and the CORS-settings!), I add my API app to my logic app by first selecting "App Services", and then your API App.After that, start using your output, e.g. in a mail. For testing it out I created some view, that allows me to "change" the weather. If that happens, the logic apps starts working (and sends me a mail). For completeness I'll give the full code for my API polltrigger underneath. Next time : Push triggers !! public class WeatherController : ApiController { [SwaggerResponse(HttpStatusCode.Accepted)] [SwaggerResponse(HttpStatusCode.OK, "triggered", typeof(WeatherInfo))] [SwaggerOperation("CheckWeatherReport")] public HttpResponseMessage Get(string triggerState = "") { if (string.IsNullOrEmpty(triggerState)) { triggerState = DateTime.UtcNow.ToString(); return GenerateResponse(HttpStatusCode.Accepted, triggerState, "15"); } else { if (DateTime.Parse(triggerState) < DateTime.UtcNow && WeatherReport.Changed) { WeatherReport.Changed = false; triggerState = DateTime.UtcNow.AddMinutes(2).ToString(); WeatherInfo info = new WeatherInfo() { ChanceOfPrecipitation = 80, Temperature = 8, WeatherCondition = "Storm" }; return GenerateResponse(HttpStatusCode.OK, triggerState, "15", info); } else { return GenerateResponse(HttpStatusCode.Accepted, triggerState, "15"); } } } private HttpResponseMessage GenerateResponse( HttpStatusCode code, string triggerState, string retryAfter, WeatherInfo data = null) { HttpResponseMessage responseMessage = Request.CreateResponse(code, data); responseMessage.Headers.Add("location", $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}/api/weather?" + $"triggerState={HttpUtility.UrlEncode(triggerState)}"); responseMessage.Headers.Add("retry-after", retryAfter); return responseMessage; } }
Creating connectors for your Logic Apps/Flow (Part 1–regular Connectors) 24 February 2017 Michael-Van-Wesemael Office 365, SharePoint, Azure, Logic Apps, API Apps, Flow Azure logic apps have been around for a while now, most of the time as a preview. These apps allow you to create workflow-like apps, by connecting so called Connectors together. These connectors are actually just REST-services, with some extra's, like the exposure of metadata by using Swagger. These Logic apps have also been made available through Office 365, where it is known as "Flow". Office 365 Flow, or Azure Logic apps have access to a library of Connectors, like connectors for Twitter, Facebook, Outlook Mail and Calendar, SharePoint and many more. At the moment I write this there are 84 connectors available. But of course we can add our own connectors. You can find information on how to do this on the internet, however I found myself struggling with Azure because of incomplete information, even in the official Azure documentation. So, I decided to complete the information. From a developer perspective, there are two types of connectors we can create: "regular" connectors and triggers. A regular connector can just be used within your flow, but not at the start. It can take input from connectors preceding it in the flow, and it can return output to the flow. A trigger can be used in the beginning of a flow and is responsible for starting the flow. Creating a regular Connector Connectors are REST services. In my example I will do this with Web API, but it can be done in any other web-technology. While creating a web application just choose Azure API App. I will create a simple example in which I just reverse an incoming string. The code is pretty simple : [SwaggerResponse(HttpStatusCode.OK,Type =typeof(StringManipulator))] [SwaggerOperation("GetReversedString")] public IHttpActionResult GetReversedString(string id) { var temp = ""; foreach (var item in id) { temp = item + temp; } return Ok(new StringManipulator { Original = id, Reversed = temp }); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } However, the second argument in your SwaggerResponse-attribute, the Type, is super important. Without this argument Logic apps, using your API, will just assume your function returns nothing ! It took me some time to find this out, since it used to work fine without Type in an earlier version of Logic apps, and it's nor really clear from the documentation. So, beware. After deploying your API app to Azure, there are two more things to do. Locate your API app in the Azure portal, and go to the API settings. The API definition should point to your swagger metadata. Make sure you refer to it using https !!!.Also make sure that CORS is enabled for your logic app, or just use * here. After that you need to restart your app. Otherwise your logic app will not pick it up. There you go. If you want to use it in a Logic app just add the Action App Services, select you API app, and select the action you want to use. And there you go, the following connectors have access to the output of your API app. Pretty straightforward, if you don't forget the Type in your SwaggerResponse-attribute. Using API apps as triggers is somewhat more work. We'll discuss that in part 2.