POST request in PowerFlow without premium connectors

One of my tasks at work was to develop an app that allows you to maintain your employee profile. I created the app relatively easily using PowerApps and PowerFlow (or whatever the actual name is). So in itself no problem.

At the end of the process, I was able to generate a PDF export of each employee. Task done, right? That's right.

A new challange appeared shortly after: We need a Word as the export format. Sounds not too hard, even with the additional requirement to keep extra costs at 0.
Not too hard. Well, it was more complicated at the end than it should be, but it is what it is. Let me show you how it can be done.

The problem

There is a "connector" in PowerFlow that can populate a Word Document. Unfortunately Premium. So this option is out. With this, all the possibilities that PowerFlow can offer me to create a Word Document were already exhausted, because everything to do with Word is Premium. Damn it.

So I can't create a Word in PowerFlow itself. No problem, I can use a Python library. Done. Nice and easy. I was able to create a good looking Word Document using the data from my PowerApp with a python library.  So the only thing left to do is deploy that python script somewhere and send the data from PowerApps to that script. Easy right? Well, not really.

Another Problem

For the deployment of the script, I've decided to use AWS Step Functions. The process itself was great and using a payload I would get ouf PowerApps worked as expected. This is how my Architecture should look like:

Initialized Architecture

As you can clearly see a simple thing. There's is just one itsy bitsy tini wini problem: HTTP requests in PowerFlow is a Premium Feature. God damnit! Which means this architecture is not possible with the current requirements.

So I can push the data back and forth inside Office365 as I like, but as soon as the data needs to outside, you are out of luck. Time to come up with something different.

After a short research I came across this article. Perfect. In short: I can use it to trigger a lambda function via a URL. Unfortunately not quite there yet. With this trick I'm able to make GET request. No data. I'm not able to send all the data with a GET request. Why you ask? Like the minutes to the first coffee, the payload is unfortunately too long. A URL can hold a very limited amount of data and since I have a Base64 encoded image in there, this option is won't fit.

A new perspective

After some unsuccessful attempts to somehow get the data out of PowerFlow, it was time for the magic bullet. Change of perspective. Every time you have a seemingly unsolvable problem in front of you, try to look at the problem from another side. Works great. In this case, I'm no longer asking myself "How do I get the data out of PowerFlow?" but rather "How do I get the data in my Lambda function?".

Let's recap. I can trigger a Lambda function using a URL. But I can't pass the full payload as a URL parameter here. What I can also do in PowerFlow is to create a file with any content.

After some tinkering around with PowerFlow I've also discovered: I can share a file. Interesting. Since in the end everything is a file, how about I put all of these things together? Get the payload, create a file, share it, pull the data on lambda and then create the export.

Here is the updated architecture in detail:

Update Architecture of Export

Instead of sending the data from A to B, I am now pulling the data from A to B.

1 + 1 = POST

Time now to put all components together. The PowerFlow looks now this:

  1. the payload is created as a file payload.json.
  2. a share link is created for the file.
  3. the lambda function is triggered with the "Upload from URL" connector.
  4. the generated data will be deleted (not shown in the picture).

The crucial part in the link is this
?share_link=@{encodeUriComponent(concat(outputs('Create_share_link')?['body/WebUrl'], '?download=1'))}

Taken apart, it consists of 5 parts. First I add the parameter share_link. The value for this is then created with a function. In there the encodeUriComponent makes sure that the whole URL is encoded. concat accordingly merges the generated share link with ?download=1. This additional parameter is important so that the file is downloaded directly when the share link is called, means I can read the file directly in Python. The outputs('Create_share_link')?['body/WebUrl'] part is simply the link generated in the previous PowerFlow step.

My Lambda function looks like this accordingly:

import json
import boto3
import urllib.parse
import requests
from ast import literal_eval
import os
import re

def lambda_handler(event, context):

    params = event["queryStringParameters"]
    encoded_url = params["share_link"]


    regex = r"(?<=https:\/\/)(.*?)(?=-my.sharepoint.com)"
    match = re.search(regex, s)

    if (match.group(1) != os.environ['SHAREPOINT_SITE_ADDRESS']):
        return {"message": "WRONG COMPANY"}
    
    url = urllib.parse.unquote(encoded_url)

    r = requests.get(url, allow_redirects=True)

    data = literal_eval(r.content.decode("utf-8"))
    
    payload = {
        "payload": data,
    }
    
    stepFunction = boto3.client('stepfunctions')
    response = stepFunction.start_execution(
        stateMachineArn=os.environ['STEPFUNCTION_ARN'],
        input = json.dumps(payload)
    )
    
    return {"message": "OK"}

In short, this function gets triggered from Powerflow and it provides the shared link in the queryStringParameters. As a small security check is also present. It simply checks if the request is coming from the right organization. Then it simply reads the payload from the file and is sending it over to a step function, where the word export is created and sent to the requester.

If you like, you can also add another layer of security and ask for a passphrase in another URL parameter.

Overall I call this: Mission accomplished.

Conclusion

In conclusion, developing an employee profile maintenance app using PowerApps and PowerFlow taught me the importance of being resourceful when facing limitations. Although the necessary connector in PowerFlow for generating a Word document was a premium feature, I was able to find a workaround.

Additionally, when faced with the challenge of transferring data from PowerFlow to AWS without using a premium connector, I was able to take a different perspective and found a solution by creating a file with the payload and using a share link to transfer the data.

This experience showed me that with some creativity and resourcefulness, it's possible to achieve desired results even when facing limitations. It also emphasized the power of combining different tools and technologies to find solutions that meet specific needs.mitations.

Tell me on Twitter if you faced a similar problem and how you was able to find a solution