Schedule API Workflow vs. Schedule API Workflow on List - Data Types

I’ll walk through this step by step so everyone can follow what I’m talking about:


“Schedule API Workflow on a List” allows you to define a Type of Things here:

This allows me to choose Types that INCLUDE API data - In my example: “Grab All Tasks - IncludeDescendants data” - Which is GREAT if I am taking data from my Repeating Group and placing it in here:

With that out of the way, let’s compare to “Schedule API Workflow” - As some background, I am currently in the process of converting all of my “Schedule API Workflows on a List” to “Schedule API Workflow” (using the recursion method of calling the Schedule API Workflow again to loop).

However, note that when I go to add a “Schedule API Workflow”, there is no Type of Things:

Ok, no problem, I’ll just make sure to put in the Data Type into the parameters on the Endpoint:

And this is where I get to my frustration… When you click on the dropdown for Type, it does NOT include API data for “Grab All Tasks Include Descendent Data”… So I can’t just take my Repeating Group data and put a piece of it into my parameter.

The parameter dropdown on the endpoint only gives me access to the Data Types I have in my Bubble Database or just the usual “text”, “number”, etc.

I’ve worked around this, of course, but I’m not sure why the Type on the Parameters doesn’t allow me to choose a data type that is an API like “Schedule API Workflow on List” does.

Would save me some time on creating the looping “Schedule API Workflow”… Frankly, “Schedule API Workflow on a List” was so much easier as it gave me the ability to take the Repeating Group on my page and slap that data into the “Schedule API Workflow on a List”.

More of a rant than a cry for help as I’ve already re-done all of these… Happy Friday!

I know this an old post, but wondering what work-around you used? I’m running into the same issue. I would also prefer to use the recursion method of calling Schedule API Workflow (instead of Schedule API Workflow on a list) to save the external api data to the database, but without being able define a “Type of things” I can’t seem to feed my list from the api call in to “Schedule API Workflow”.

It’s nasty – You have to break out each individual data type in your external API call.

Let’s say I have an external API call for “Cities in the US” – This fake API returns the name of the city (text), zip code of a city (number), and geocode (number).

I want to give my Schedule API Workflow a list of 100 cities and have it run through them all.

Instead of being able to pass in “Cities in the US” data type, you have to pass in each individual piece of data when you make the call.

So, in my backend API workflow, I create the following endpoint:

Key: city | Type: text (LIST)
Key: zip code | Type: number (LIST)
Key: geo code | Type: number (LIST)

When you go to make the call in “Schedule API Workflow” on the front end, your call will look like this:

Cities in the US’s data: each items’s city
(Cities in the US is a “Get data from external API” call")
Screen Shot 2022-01-03 at 3.55.15 PM
Cities in the US’s data: each items’s zip code
Cities in the US’s data: each items’s geocode

This will send to the “Schedule API workflow” 100 cities of type text to your backend workflow, etc etc.

From there, you can iterate on it as usual with the API Workflow itself.

Thank you for this answer! I tried it out this morning and was able to get it to work.

Unfortunately, I ran in to an issue where Bubble is removing the duplicates from my API data, so I may be stuck with Schedule API Workflow on a List.

Unfortunately, I ran in to an issue where Bubble is removing the duplicates from my API data, so I may be stuck with Schedule API Workflow on a List.

Yeah, Bubble doesn’t allow duplicate entries in lists, which can be a problem here…

You might want to take a look at the List Popper plugin, which is ideal for this and allows duplicate on lists.

Thanks! I have tried List Popper but ran in to a separate issue when the API response omits a key-value pair (which will happen often in my case).

For example, the Plaid API response data looks like this:

The cost_basis key-value pair is omitted in the 3rd and 4th entries (i.e. Plaid does not have that data available, so they omit it in the response).

If the data type of the key-value pair is “text”, then List Popper appears to insert “null” in the list in place of the “missing” entry. This is great - I can work with this!

BUT, if the data type of the “missing” key-value pair is “number”, List Popper does not insert “null”, it just shortens the list.

When I try to save these lists to the Bubble database, I get mismatched entries due to the missing values.

(FLOW State SSA is not necessary for my workflow. I only included the FLOW State List SSA to highlight the missing “null” values. I was also trying to understand why FLOW and List Popper work differently in case that helped me towards a solution.)

@keith I’m confused as to why it seems like List Popper handles the two data types differently. (A very likely explanation is me doing something really wrong, but I can’t figure out what it is!)

1 Like

Hi @melissa7 this is a very interesting question. What’s going on here (unfortunately) has to do with some sanitization of how Bubble handles arrays. I’d never specifically come across this exact example (and it’s a good one), but to understand what’s going on:

[Correct me if I’m wrong on this first point…] The API connector returns to you a List of "Statics" yes? And then, you are accessing a List of Static's data's ticker_symbol (which resolves to a list of texts) and separately a List of _classes's data's cost_basis (which resolves to a list of numbers). Anyway, it’s something like that, right? Or maybe it’s just a single object called “_class” or something.

And you are feeding those as inputs to two different Flow State Lists SSAs in the hopes that you now have two “parallel lists” – one of the ticker symbols and one of the corresponding cost bases. (You’re not being crazy to expect this, but that’s not how this works.)

However, sometimes you find there are a different number of elements in these two lists. (Missing values for the text list show as null and missing values for the numeric list are… well… just missing, right?)

I’ll explain why later, but in the meantime, here’s the tl;dr: DON’T SEND THOSE SUBLISTS TO MULTIPLE LIST POPPERS. Send the list of top-level objects to one List Popper. In your case the API Connector is sending you a list of "Static"s maybe or maybe it’s called a “_class”, I’m not sure. (Maybe it’s a list of "data"s? You could also send that.)

Anyway, when you do that, what List Popper returns to you is a SINGLE, SCALAR ITEM (it’s what we call an object in JavaScript, but Bubble calls it a “Thing”) held in the Popped Item output of List Popper. And, when you access the properties of that thing (List Popper’s Popped Item’s Some Property), you will get JUST THE VALUE FOR THAT INDIVIDUAL thing. In your case - when you do this right - that singular thing will have (for example), both a ticker symbol (singular) and a cost basis (singular) property. AND ONE OR THE OTHER OF THEM MAY BE EMPTY. But you will now know - “oh hey, this item has no ticker symbol” because List Popper's Popped Item's Ticker Symbol or List Popper's Popped Item's Cost Basis will be empty. And you can handle that as you see fit.

(I assume what you’re doing here is attempting to parse the API response into real Bubble objects and store them in the database… Since the API Connector’s version of the response is unusable in Bubble terms – I call these List type responses “API Ghetto” datatype.) Anyway, to make this work as expected, you send List Popper the list of objects that’s just above the individual items you are trying to parse. For example, if Blargs have a Foo and a Bar, send List Popper the list of Blargs and then as you iterate, you can inspect each Foo and each Bar, even if they are empty.

So here’s the “too long” part:

What’s going on does not relate to the code for FLOW State SSA nor to the code for List Popper SSA, unfortunately.

When, in Bubble, we look at an item that is a List and we then ask to give us the value of some property of the items in that list (by writing Some List of Things's Property), we wind up with a Bubble List that is of some type.

And every individual Item in the List must be of the same, singular type. So – as in your example – the list might hold some texts or the list might hold some numbers, but there’s no such thing (generally) as a List in Bubble that contains BOTH some numeric values and some text values (for example).

This is not that case in JavaScript, where I can make an array that contains any sort of data types that I want. I can make an array that mixes different types of data (and those individual items might even be arrays or objects themselves!). For example, here’s an array that has both strings (what Bubble calls “texts”) and numbers in it:

var myarr = ["ABC", 1, 2, 3, "baby you and me, gurl"]

The first value is a string, the second thru fourth are numbers and the last one is a string.

Now, JavaScript arrays can also contain empty values, that are typically indicated by a special value called null. And, in fact, in Bubble the concept of empty is very similar to the concept of null. I could go on a lot about this but it’s not entirely relevant to the conversation at hand.

Anyway, when you ask Bubble to take that list of (number type) Cost Bases into FLOW State SSA, the LOG MESSAGE you’re seeing (the one where you see numbers as well as nulls) isn’t what’s stored in FLOW State, it’s what’s going into FLOW State. And it’s a representation of the raw API response.

But THERE IS NO VALID REPRESENTATION of this JSON object in Bubble land. You could argue that there SHOULD be, but Bubble isn’t having it. That object gets converted into a proper Bubble list at the input of FLOW State. And, in a case like this (numeric list), it seems the nulls essentially get stripped out.

Inside of FLOW State (I’m talking about the actual code), we use a Bubble plugin API method (List.get() )to fetch the contents of this List. And what we get back is just the numeric values… the nulls (somewhere in Bubble’s own code) get stripped out. Bubble doesn’t let numeric Lists contain anything but numbers and null is not a number (it’s an object, actually).

Now, why is the handling different if the List is of type text? Well, there is such a thing as a null string and null does have a string representation, so it seems Bubble lists of text type allow nulls.

For example, if I have an array of strings and nulls like so:

var keith = ["one", "two", null, "three"]

This can be easily converted to a text representation of the entire array, by saying:

keith.toString()

which will yield the string:

'one,two,,three'

Or I could do something like, convert each individual element in the array to a string by:

keith.map(item => String(item))

which will give me an array of strings like so:

['one', 'two', 'null', 'three']

The above doesn’t really explain exactly why Bubble chooses to do this (and why it shows up in server-side plugins or in the API Connector, or whatever), but that’s just what it does.

I note that, if you create a very simple Server Side Action plugin with code as follows:

function(properties, context) {
        
var numlist = [1, 2, null, 4, 5, null, 7]
var stringlist = ["One", "Two", null, "Four", "Five", null, "Seven"]

return { "numeric_list": numlist, "string_list": stringlist }
}

The lists that come back into Bubble when this is executed abide by the same rules I described above: We get a list of 5 numbers and a list of seven “texts”, two of which are null:

Anyway, the results of your two list expressions cannot be guaranteed to have the same number of values, so what you do is send List Popper the list of objects you are interested in and then, in your iterative workflow, you examine the property values individually (by looking at the single, scalar Thing exposed by the Popped Item output of List Popper). Obvs, you then call the same workflow again, sending it the contents of the Remaining List output.

2 Likes

One quick addl note: if the only reason the price would be empty is that the ticker is empty (and vice-versa), you could use the approach you’re already using but filter the ticker list using each item/this item: is not empty filter (this would remove your “extra” nulls in the ticker list.

Thank you for this detailed explanation. This makes a lot of sense now (even to my non-coder brain :slight_smile: )

I suspected that I needed to be using the top-level object instead of the sub-list (as you mentioned) but wasn’t quite able to feed it in to List Popper correctly. I will give it another try with fresh eyes today.