I have a shortcut that uses Get Contents of URL to POST some data to an API. I have everything working, except that I want to be able to include tags with the posted data.
The API expects tags to arrive as a list, as part of the JSON body of the POST. I am able to present the user with a list of tags with multiple selection, then save that list into a Shortcuts variable. As far as I can tell, Shortcuts treats that as a list. However, when I try to pass that variable to the API as part of the JSON body, I get an error. (Not sending tags at all resolves the error, so I’m pretty confident that’s where the problem is.)
Anyone have tips for passing a list to an API as part of a JSON payload using POST?
As an alternative, here’s an example that uses the conversion process I have tucked away in a corner of my Shortcuts library.
The general approach is unsurprisingly quite similar to the approach shown in the example above. In comparison to that example, it accounts for some additional content variations you might typically encounter. Most notably entries with multiple lines and escaped (back slashed) content.
For large lists it should also be more efficient as it processes all list elements as a whole for the find/replace rather than on an individual element basis. For smaller lists, which for most APIs would be the more commonly encountered structure size, it should be comparable in speed but certainly a little slower as it is accounting for the additional data variations. If performance is a key consideration, simply remove any find replace options - e.g. form feeds.
I tried something similar. Putting the resulting variable into the JSON body as a text item didn’t work — maybe the entire thing gets wrapped in quotes? I’m not sure because I haven’t figured out how to inspect the payload. But I’ll give it another try in case I did something wrong the first time around.
So I can change the list to text — since I’m using just simple one-word items, I join using ”,” and then wrap the results in [“ ... “] which yields the same end result and your more comprehensive approaches.
However, when I try to insert that into the POST body, I get an error from the API:
{"tags":["Expected a list of items but got type \"unicode\"."]}
I think the problem is that the Get Contents of URL action does too much work for me — I have to choose the datatype for each item in the Request Body, and by choosing text, it must wrap the whole result in quotes, so that the valid JSON array ["Apple", "Orange", "Banana", "Pear", "Grapefruit"] becomes ”["Apple", "Orange", "Banana", "Pear", "Grapefruit"]”
By contrast, if I set the datatype to Array, I can enter individual items, but I don’t see a way to programmatically feed it the items of the list I’ve created. This seems like a serious shortcoming.
The only other alternative I see is to try to turn all the elements of the request body into a JSON document (rather than specifying individual components and letting Get Contents of URL turn them into valid JSON). But so far I haven’t gotten that to work either.
Wow. Ok. I’ve solved it for my particular use-case (which is adding a task to Taskwarrior, the command-line task manager, via inthe.am, a sync service for Taskwarrior).
I had to turn the various components of the JSON to a single text variable, formatted with curly braces and all so that it’s a valid JSON object. Then in the Request Body section of the Get URL Contents action, I selected File (instead of JSON or Form). In the File field, I put the token for my full JSON object.
Here’s the tricky part: I then had to tap on that token, and set it to send the variable as Dictionary (rather than as text, file or any of the other options), with the key setting blank (to send the entire object). Not intuitive.
Happy to post screenshots and/or the final shortcut if anyone would find it useful. Thanks for your feedback — it confirmed that I was executing my initial approach correctly, but it just wasn’t going to work. Sometimes identifying the dead ends is useful too!
What I don’t get, yet, is why it is apparently only working when set as a dictionary. But I have one theory…
Looking at the unicode reference in the serialising error, and your examples above, I can see one thing that might explain it … if it isn’t just a forum specific typo. Your examples are wrapping content with smart (double) quotes rather than (standard) double quotes.
i.e.
Above it shows
[“ ... “]
rather than
[" ... "]
If you were doing that, that could explain the error.
Thanks. Looking back, im pretty sure the “smart” quotes are just a function of entering the snippet here in the forum editor.
When I used the JSON option for the Request Body, I assumed it turned the combination of the sky-value pairs I entered into a JSON input. That’s why I was trying to add a list of tags to a tags key. Is that not the case?
Fwiw, I did initially try to use the File option and send the fullly assembled JSON payload, but until I hit on sending it as a dictionary (by systematically trying every remotely reasonable option…), I got errors that way.
JSON is a plain text file format. It should be absolutely fine to pass as a text string. I would expect you to build a text string to pass into the API.
However Shortcuts can translate from JSON to a dictionary and back. If you are entering key value pairs then maybe there’s something about how you are specifying that in the dictionary that is off.
But the fact the error specifically references unicode previously really flags whatever generated that issue as character set related which means one of more characters were probably in some sort of unexpected format and I still wonder if it was something more structural than data specific?
But it could even be that it is something API specific. Even a venerable language like Python has had JSON encoding challenges…
iOS 17 lets you assign a variable to an array or dictionary value in a dictionary. No more tricky hacks for API calls. (This makes your shortcut iOS 17-only.)