JSON REST API- Accessing Same Data in an Array, but Called from Different Components

Hi,

I’m testing an air quality REST API returning JSON. If I use an array to attempt to bind a component to a data variable, such as “AQI”, I am unable to do so because I get an “incompatible” error stating: The type “list of objects with 11 properties” is not assignable to the type “text / number”.

Here is an example of the data:

[{
“DateIssue”: "2020-10-22 ",
“DateForecast”: "2020-10-22 ",
“ReportingArea”: “Phoenix”,
“StateCode”: “AZ”,
“Latitude”: 33.543,
“Longitude”: -112.071,
“ParameterName”: “O3”,
“AQI”: 77,
“Category”: {
“Number”: 2,
“Name”: “Moderate”
},
“ActionDay”: false,
“Discussion”: “Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.”
}, {
“DateIssue”: "2020-10-22 ",
“DateForecast”: "2020-10-22 ",
“ReportingArea”: “Phoenix”,
“StateCode”: “AZ”,
“Latitude”: 33.543,
“Longitude”: -112.071,
“ParameterName”: “PM2.5”,
“AQI”: 60,
“Category”: {
“Number”: 2,
“Name”: “Moderate”
},
“ActionDay”: false,
“Discussion”: “Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.”
}, {
“DateIssue”: "2020-10-22 ",
“DateForecast”: "2020-10-22 ",
“ReportingArea”: “Phoenix”,
“StateCode”: “AZ”,
“Latitude”: 33.543,
“Longitude”: -112.071,
“ParameterName”: “PM10”,
“AQI”: 79,
“Category”: {
“Number”: 2,
“Name”: “Moderate”
},
“ActionDay”: false,
“Discussion”: “Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.”
}]

If I remove everything but the first object in the array, and add it as a new data variable - configured as single data record instead of a collection of data records, I can bind any one of those properties to a component without issue.

Both data resources pass (as Status: OK) when I run a test. But when I click “Set Schema From Response”, they both generate the exact same schema - even though one is an array and the other is not.

Do I need to manually create schema in order to access a specific property result from the second or third object in the list?

Am I even asking the right questions? :wink:

Thanks

Hey there!

In this case the error message is telling you what is wrong:

The type “list of objects with 11 properties” is not assignable to the type “text / number”.

Which is saying you’re trying to bind a list of objects to a “text / number” type property.
Now without touching your data variable, if you would want to pick out the 2nd “AQI” value, then what you could do is bind with a formula like:

dataVars.nameOfYourVariable[1]["AQI"]

Which is now accessing the 2nd object (1 when indexing from 0) from the list and then a property named “AQI”.
The schema in the data configurator refers to the data object’s schema, so it is correct that it displays the same for collection and single result, however for collection you should be getting a list of objects and for single record a single object :slight_smile:

Thanks for your reply @Akseli_Virtanen. I really appreciate you taking the time to look into this!

So I did a test using just formulas (like so: data.AirNow850011[0]["AQI"]), referencing the same data variable (the one with a “list of objects with 11 properties”), and I was able to assign the various AQI to different components. So it seems to work. :sunny: Very cool!

I have a follow-up question: The JSON array is the data variable I need to be using. I’m concerned that my only option for accessing the list of objects within it is by using formulas. Is this normal, or is this a workaround because of some issue or limitation with the data feed?

Regarding schema, they are precisely the same for collection and single record:

The single record (AirNowPhoenix) just has the one JSON object with 11 properties. The collection (AirNow85001) is a list of 14 objects, each with those same 11 properties, but containing different results for each object. For the collection, I’m not seeing the list of 14 objects.

Here is a link to an example of that JSON collection: https://www.webmagi.com/data/json/array.json

So does the screenshot of the schema for the collection (AirNow85001) jive with the actual JSON example link?

Thanks.

Sorry for asking, but I’m relatively new to using formulas. Does anyone know how would I access the property Name within the Category object in the screenshots above? I need to assign Category.Name to a component, but these two formulas do not work: data.AirNow850011[0]["Category.Name"] and data.AirNow850011.Category[0]["Name"]

Just for contrast, for the single record data variable, I can manually select the Category Name:

Not sure why I can’t do this with the collection? It would be so much simpler!

Thanks

@Anthony_Williamson

  1. For the schema view, it is completely correct that they display the same schema. The returned data is different though, as GET COLLECTION returns a list of objects and GET RECORD a single object. However since the interesting schema in both cases is the object schema, Composer simply displays the object schema for both.

  2. As for the list of objects collection. Here Composer won’t allow you to bind anything from a inside a list directly to a component. This is to reduce complexity and inevitable errors, as lists can contain other lists and so on. You can still do this in formulas, but the difficulty is an indication that maybe you should not :slight_smile:

Now there’s another way you could make selecting a single object from a list more ergonomic:
you could bind “repeat-with” property with a formula like data.AirNow850011[1] which now selects the 2nd object and inside the “repeat-with” you can bind to the current object properties which gives you the same UI as with a single object.

You could of course also use the formula to store a single object into a page variable as you’re fetching the data.

Finally a note on the syntax: both [] and . are used to access properties. The [] are useful when using is not possible .

So for example:

object.name and object["name"] are the same thing.
list[0] would be equal to list.0 however the latter is not legal syntax in formulas
You can also mix and match list[0].object["name"]

Hope these help!

@Akseli_Virtanen,

My apologies for being such a noob here with regards to how AppGyver works with JSON API, but am I to understand that we should only expect to work with simple JSON APIs; ones that are mostly single records based, and not an array? And should our best option be to use such a complex JSON API; one which has a large array of objects, should we only expect to be able to easily access the properties within any given object by using the “Repeat with” binding… even if the component in question is intended to be a standalone component, and not a list of items?

I am working on creating a US-based Air Quality app, utilizing air quality data from open resources like the EPA’s AirNow service and possibly PurpleAir, which has a very large and publicly available JSON feed. One of the primary features that I must include, is the ability for a user to either input a zip code, or a city, and have the results show recent air quality for that location. There are thousands of air quality sensor stations throughout the US, so I must use a data source that can provide the most complete results, and this will undoubtedly come in the format of a very large array of objects, each with properties that I will need to easily and quickly access on a per-component basis, and not necessarily as a list of items. Does this sound like a project that AppGyver can handle at this time?

Again, my sincere apologies for my lack of knowledge for how AppGyver works. This project came to me only a few months after Composer Pro was released, so this is my first mobile app project with you. I hope to have many more! :blush:

Thank you!

1 Like

@Anthony_Williamson

On the contrary, Composer can quite easily handle large amounts of data. What I was trying to convey is that trying to bind data from a large list of objects to a single component doesn’t make good programming sense, (which is why it is not possible to do without workarounds), and that there are better ways (likely) to achieve the same results :slight_smile:

However I don’t know quite enough about the structure of your application to outright recommend how you should build it. But here are some questions to think about:

  1. Where and what us the relevant data for my app? After all it makes little sense wielding a huge dataset if you only use fractions of it. Perhaps the API allows you to target based on a state or a set of values?

  2. What’s the hierarchy in the data? Instead of having to dig a huge list for a single component binding, one should make use of API calls, variables and formulas to get down to the relevant information. This is why I brought up “repeat-with” as it causes the data for each of the member objects to be isolated in a much more manageable “bucket”.

So yeah, while you can do stuff like hugeList[347].fields[“details”][5] it is rarely a particularly good way of doing things :slight_smile:

Of course, that is precisely what I am trying to do. As shared in a previous reply, here is an example of a single zip code for Phoenix AZ, from a few days ago: 85001. The only objects I’m using from this single zip code output are the first 3 objects, because they repeat for the next day in the forecast, and I am not using that data right now.

The only properties I need to show in the app, from these 3 objects, are “DateIssue, DateForecast, ReportingArea, AQI, Name, and Discussion”.

And at this time, this is the layout for those data properties:

Ozone is [0][AQI], found in the first object in the list.
PM2.5 is [1][AQI], found in the second object in the list.
PM10 is [2][AQI], found in the third object in the list.

I only need to use the “Discussion” property once, which you can’t see in the screenshot.

But here’s the thing, users can be anywhere in the United States - looking for the Air Quality Index for their area, by inputting their zip code. So while the components in the screenshot only need a very small set of objects and properties to function, the Data Resource (JSON Feed) must contain all zip codes from the available reporting stations.

You mentioned using API calls. Is there documentation for using them in AppGyver?

And considering we are even having this discussion about large data sets and large list of objects, do you have any tutorials that touch on this, showing how AppGyver should be used in these situations to display simple data as shown in my screenshot?

Hi, I have a follow-up question:

Instead of using “Set Schema From Response” after running a test, could using custom schema help me to better drill down into just those properties I need to display in the app at any given time? And if so, how could these be used with API Calls to target specific objects (such as a zip code, city, or state for example)?

Hey :slight_smile:

So a pretty common way to setup something like this would be that:

  1. You provide some way for the user to enter a zipcode / select a state etc.

  2. Based on that you query the REST API for that specific piece of data (like say to get a single posts you’d be able to do something like /posts/1)

With this setup you typically only have one page with a changing identifier/identifiers to request the specific data you need from the API. In your example you didn’t show the API, but just the JSON data piece, so I can’t really give more details in this specific case :slight_smile:

The custom schema won’t of help to you in this case, as it does not affect the return value from the API.

What you can do is use the “response key path” setting to access through levels of the return data.
Say if the API returned something like:

{
"results": {
   data: [...]
   }

In this case you could set the “response key path” as results.data to have only the contents under “data” filtered to any data variables you create from the resource.

If you can point to some documentation for the REST API I’m happy to assist further!

Hi @Akseli_Virtanen,

My apologies for the delay in getting back to you. I decided to work on other parts of the app first. I will revisit the zip code input and JSON data feed a little later on. I will dive into your recommendations at that time. I’m sure I will have questions, but I love the logic of it! :slight_smile:

Thanks!