Standing on the Shoulders of Giants
Updated: Nov 7, 2019
Don't let the premise scare you. While you will see links like 'developer' in the sentence, trust me that you don't need to be one in order to build an Alexa skill and integrate it with Microsoft Flow / Power Automate. In fact, if you've read my article on Microsoft's natural language interface, LUIS.ai, you've got a great foundation for working with Amazon's interface.
First, let's discuss my intent: This is part of a series...a journey, if you will...as I work to build a hands-free approval process using Microsoft Flow / Power Automate and Amazon's Alexa (as well as some other cool stuff). It begins by letting the user know they have an approval, and in this article I explained how to add that notification to any flow. This works as long as the person adds that step to each particular flow, but as part of this step, we will build a secondary flow that will trigger a notification regardless of if the step is included in each approval flow. Next, we'll review the steps in a draft format, and then we'll build a basic version and leave room to improve with successive iterations. This will be fun.
A little bit on what I've learned about Approvals in the Common Data Service so far: There are three entities that I've found relating to Approvals.
Approvals - Houses the information for the approval itself. For this record, the Owner is the person who created the Approval.
Approval Requests - Handles the requests sent to each "Approver". If an Approval is sent to multiple people, there will be multiple Approval Requests tying to a single Approval via the Approval field. For this record, the Owner is the "Approver".
Approval Responses - As it sounds, this would be the response from the "Approver". I can't imagine there would be multiple responses for a request, but it's probably possible (in case someone changes their mind?). On this record, the Owner is also the "Approver".
Triggering a notification off of a new approval should be relatively simple. We will set a trigger on the Common Data Service's Approval Request entity, grab the title from the actual Approval, and then grab the owning user's name to filter for just requests sent to me. From there, we'll initiate the same Alexa notification from this post.
And then the criteria and action:
The downside here is that the flow will trigger with every Approval Request before filtering to just mine. There are probably ways around that, but since I'm not concerned with my quantity of runs, this is the path I'll go.
Next, the real fun. We'll begin by creating the skill in the Alexa Skills developer console. You can sign in with your existing Amazon credentials, or create a new account just for this (it's free!). If you're the tl;dr type, check out this video from April Dunnam and Jon "The 's' is 'ilent'" Levesque. Otherwise, rock on below.
Once you're logged into your Amazon Developer Console, click on Alexa and then Alexa Skills Kit:
From the next screen, click "Create Skill", give your skill a name, and keep the default options ("Custom" for model and "Provision Your Own" for backend resources), and finally click "Create Skill". On the next screen, continue with the default of "Create from Scratch".
Now, we're in the mix.
Don't freak out. It looks busy but all of this is manageable when we break it down into small enough bites...and, you won't have to write any code (I promise).
Along the right side is all of the steps we need to complete this, and Amazon has done a great job of making this easy. We won't do them all in order, but you'll have no trouble getting through this.
First, we want to edit the Invocation Name. This is the thing that is going to 'wake up' the skill. If you're familiar with Alexa already, you know that for most third-party skills, you need to "ask <invocation name> to <do the thing>". I called mine "Approvals", so that I could simply say "Alexa, ask Approvals to show my open requests". Once you've picked the invocation name, click "Save Model" in the top left.
Now that we've 'woken up' our skill, we need to define the <do the thing> part. There are a couple of layers to this, though. Just like with my Teams project, we have an intent (the thing) but without a layer of natural language, we have to get the phrasing exactly correct. Both Amazon and Microsoft use 'utterances' as a way to allow some latitude between the request and the action. We'll begin by creating the intent.
The easiest way to do that is to click the next step on the blocks on the right of the Alexa Developer Console and select "Add Intent". Give your intent a name (I used listapprovals), and then "Create Custom Intent". You will be taken to the utterance screen, where you should enter at least five phrases that someone might use to do the thing.
Once you've finished, click "Save Model" and now it's time to work on our Flow.
I won't mislead you. Building this flow was a bit of a beast. There were so many elements that I had to reverse-engineer so that I could explain them properly, and there were so many things that I just didn't know how to do. Fortunately for all of us, there is a super-smart community out there, eager to help when you run into trouble. I leaned on a LOT of people for this, and I'm ridiculously grateful to all of them. My hope is that this will give folks the confidence to try something way outside of their comfort zone, knowing they have support if things go sideways, and possibly learning some things along the way.
Sketching out the Flow, it will begin with an HTTP request (this and the CDS connector we're using are both PREMIUM connectors). Because I want Alexa to read off the approvals with an item number ("Approval #1, <Title>"), we'll need to initialize an integer variable and an array variable. The array will temporarily hold the results of our search.
Next, we'll list all of the Active approvals in CDS, and then we'll list the associated Requests for each of these (remember, there can be many Requests for each Approval)...filtering out only active Requests, as well as only the ones belonging to me, along the way.
For each successful result from that list, we will increment out integer by one, and then append some information to our array.
Finally, we'll JOIN all of the array results into a single string so that we can send it back to Alexa in the proper format using the HTTP response.
I know it sounds hairy, but I did all of this without code (I had to use some OData filters, and copy/paste some JSON, but you can totally follow this recipe). You got this.
Open a new flow and use the trigger, "When a HTTP request is received" and click "Use a sample payload to generate schema" at the bottom. Next, go to Jeff Hollan's Git Repository and open the AlexaRequestSchema.json file. Click on the button that says "Raw" in the top right, and then select all (ctrl-a) and copy (ctrl-c) the results. Then, paste (ctrl-v) those into the sample payload window you just opened. Click "Done" on that window, and you're back to your trigger, but now it has schema. Fun, right?
Next, initialize your variables and save your work. Notice that you now have an HTTP POST URL up at the top of your trigger. We'll use that later.
My usual caveat, again, is that there are going to be more elegant ways to do this...but this is the way that worked for me. Feel free to find your own way, that's part of the fun.
For the next step, I used List Records and chose to find all of the active Approvals. My thought was that this would be a smaller list than active Requests, and I was hoping it would speed things up. Here is where I did my first OData thing by looking for the active status. For reference, several people pointed me to Kent Weare's article on Filtering Data with OData.
After this, I listed the Approval Request records and added an OData filter that did a few things: Only presented Request records that were owned by me (meaning I was the approver), were active, AND matched a record in the Approval list. This last part makes Flow kick off an Apply to Each loop because it's comparing each request record, one at a time.
Note that the field names don't have single quotes around them. This, apparently, is a 'thing' with Flow so check that if you ever bump into trouble. Also note that any integer values don't need quotes.
If you're wondering how to find the values and field names, one trick I use is to either run the Flow to get the output data from the previous step, or have another small Flow that has a manual trigger and then whatever action I want to test. After that, you can review the output in an online JSON editor to make it easier to find the values you want (like owner_id).
Because this is going to append to my array with some additional text, AND because it's getting the Request information while it's going through one at a time, I want to make sure there is output from the filtered list before appending that particular row to the array. Otherwise, I'll have my added text, "Approval #" and then no value for each of the active Approvals that didn't have a matching Request assigned to me. To do that, I just added a condition within the loop, which checked the length of the output. I've put the expression in the caption, but you can just type "length(" in the expression box and click on your own dynamic value. I didn't type mine out from scratch.
Once Power Automate / Flow has gone through all of the Approvals, the array variable should be complete. But our response back to Alexa requires it to be all one string, so we'll use JOIN to concatenate all of the results together, separated by a semi-colon.
Lastly (for the flow), I want to have a path if I have no Pending Requests at all, so I'll check the length of the JOIN output. If it's zero, Alexa will respond with "There are no pending approvals", otherwise our list will be presented.
For the Response Body, April Dunnam has graciously provided the JSON she used (AlexaResponseBody) here. I just altered the "text" to suit my Flow.
Before we head back to the Alexa Developer Console, be sure to copy the HTTP POST URL from your trigger.
Back at the AleDevCo (I'm making that a thing), we want to paste that URL into the endpoint section. You can either click on the big button on the right of the home console page, or the "endpoint" tab on the left rail.
On the next screen, select the HTTPS option, and then paste your POST URL into the box at the top labeled, "Default Region". In the dropdown below that, be sure to select the option, "My development endpoint is a sub-domain of a domain that has a wildcard certificate...". Click "Save Endpoint" up at the top, and you're almost ready!
Go back to the main AleDevCo page (catchy, right?) by clicking "Build" at the top, and then click "3. Build Model" along the left (just above Endpoint). This starts the build of your Alexa Skill and should be done in a few minutes.
To test it, either use your Echo device, or click on the Test tab and use your microphone or type in the request. Either way, be sure to include the invocation name ("Ask Approvals to..."). Here is the complete Flow.
Again, a big "Thank You" to the many people who helped me work through this. My hope is that I was able to bump my head into everything so that you wouldn't have to.
Get in, make a mess, break something, and learn along the way. Remember the rules, if you start to get frustrated, and also remember there are loads of people eager to help.