Why send images to an API?
For a small private project, I wanted to trigger a Logic App for generated images in Azure Blobstorage, which would then display them to teams with AdaptiveCards.
The problem: some of the images were simply larger than the allowed 25KB payload of the Adaptive Card.
Which solutions are possible: certainly a lot.
- I could specify a URL on the image in the AdaptiveCard . But since I also want to change the image elsewhere and continue to use it, this is not the best option.
- I could generate the images so small that the payload is not exceeded. However, then I would no longer have the size I need for other tasks.
- Create twice in different sizes? Sure, and if I need another size, just generate another size and build up thousands of redundancies? Nope!
- Send the image to Azure Cognitive Services and get it back as a thumbnail. Really good idea, but I still didn’t do it, because I already have my own API, which already does something like this and is less cost-intensive and “complex”.
- So send to your own API ..?!
I decided in my project to send an image to my API. However, the image is expected as a file which I have to deliver with the Content-Type MultiPart/Form-Data. In the following, I like to describe how I did what works for any other file type.
Addressing an API with cURL
To send the image to an API, you can use the HTTP action. This is used to execute a normal http request on a URI. This means that you can also send anything via an HTTP action that you could with a normal cURL command. YES! Only how is difficult, because in the action not everything is “clickable”.
So what option do we have? Let’s see how we would do this with cURL:
curl -F "image=@${FILENAME}" -F "size=400" $URL
The command sends an image file (the filename comes from the environment variable FILENAME) as form-data with the field name “image”. As a second parameter, I set the desired size and send it all to the url $URL
Translate cURL to HTTP
Does knowing about it help us? Only to a limited extent! Let’s see what this would look like as an HTTP request:
POST / HTTP/1.1
Host: $URL
Content-Type: multipart/form-data; boundary=--------------------------484040840196266074159071
Content-Length: [length of the request body]
----------------------------484040840196266074159071
Content-Disposition: form-data; name="image"; filename=""[FILENAME]
Content-Type: application/octet-stream
[binary data for the file specified in the filename field]
----------------------------484040840196266074159071
Content-Disposition: form-data; name="size"
400
----------------------------484040840196266074159071--
What stands out is “boundary”. this “marker” lets the HTTP interpreter know that the form data can now be read. a “boundary” starts with two — (dash).
Then a Form field begins with ‘Content-Disposition’ and the specification of the field name. Of course, the content types are always expected (but not always necessarily).
Each field is listed sequentially with a start boundary. To send a file, simply insert its contents after an empty line (as you can see in the first boundary).
you complete the form data with –<boundary-id>–. in my example this is –484040840196266074159071– (don’t get confused… the boundary ID must simply be unique – i.e. must not appear in the text of the file)
Transfer the HTTP request to the HTTP Action
Here you can see that I use a post method.
Under URI I enter my Custom API Url.
For “Headers” I put in the Content-Type for Multipart/Form-Data, which corresponds to the above HTTP request. I called my boundary ‘testboundary’. There are no real rules for this name – important: may not be used in the following content. (which should not happen with a picture 🙂 )
Everything I explained to you in the HTTP request above comes into the body.
What you don’t know yet is, in “Outputs” I encoded the file as Base64 in preparation for the AdaptiveCard – so a complete image is always sent to teams.
In my Custom API, which runs on Azure Container App, I now read the file reduce/enlarge the image and send it back again.
Afterwards I can process the image in a relaxed way.
I hope this could help you a bit. If not, you can still try other ways. I had thought about adapting my API to the possibilities to receive a Base64 string. Or to store it again temporarily in Bloblstorage. That just didn’t seem good for my purposes – but maybe it suits you better. Who knows!