Reading/Understanding JSON to set a variable

AllOfThisPointingGIF

If you’re unfamiliar with JSON paths, this is a really good tool for better understanding things. You can paste your JSON response in the panel on the left and it displays a tree on the right that you can navigate. Each ‘branch’ you click on expands and updates the path… then when you click on a ‘leaf’, it shows your full path.

As @Nezmo mentioned, some APIs can be a bit trickier than others as they’ll return different values based on the time of day or even what data is available that day.

In that case, you have a few options depending on what data is available and what your goal is.

For example, if the current.rain.1h is only available when there’s actually rain, you could conditionally determine if you read that value or use a fallback. From what I’m reading, it sounds like current.rain is always there… it’s just that the 1h subproperty isn’t set if there’s no rain – is that what you’re seeing? If so, something like the following should work

currentRain = $context.response.data.current.rain.1h
isEmpty(currentRain) ? 0 : currentRain
2 Likes

This tool makes it easier to understand!
This is giving the brain a work-out the last 2 days!

1 Like

So trying to follow along:

Using the JSON tool I get this:

So each circled in red is between a “.” with no need for the “0” because I’m looking for the "current?

$context.response.data.current.temp

…taking small bites here…

Yes. Each ‘branch’ in the tree needs a . between it. In each of those cases, you are directly accessing a property (or branch) under the previously expanded item.

{"current": { "temp": 70.2 } }current.temp70.2

You only need the numeric indexes when there is a ‘list’ of items (array) which in the raw JSON is indicated by square brackets. And you have to access those by their zero-based index.

{"items": ["first", "second"] }items[0]"first"

Here’s a comment from another post with a primitive example:

Is there a difference between [0] and .0.?

I’ve tried them both…
$context.response.data.current.weather[0].description
title($CurrentCondition)

and
$context.response.data.current.weather.0.description
title($CurrentCondition)

Neither one returns the correct result

Thinking the first should work based on this:

No, there’s no meaningful difference for practical purposes here. The [0] format is the preferred format within expressions.

We still support the $variable.property.0.subproperty format for referencing global variables, but it wont always work with expression local variables, so it’s better to use the proper bracket format.

Is that the actual expression used? If so, it’s got a few issues.

  1. On the first line, you are referencing the full variable, but not doing anything with it
  2. On the second line, you are applying the title() function to the existing $CurrentCondition variable

If you wanted to take the description, title-case it, then assign it to your $CurrentCondition variable, that would look like:

condition = $context.response.data.current.weather[0].description
title(condition)

Ahh. this =


:grinning:

1 Like

Thank You!..

Back at it…

This has got me stumped.

Part of a rule will set a variable using the total precipitation for the day using Open Weather 3.0

RULE:

What is returned is this:

Using JSON Path Finder I get this:

{"lat":40.1817378,"lon":-80.1331118,"tz":"-05:00","date":"2023-11-17","units":"standard","cloud_cover":{"afternoon":0.0},"humidity":{"afternoon":43.0},"precipitation":{"total":0.7},"temperature":{"min":281.87,"max":292.52,"afternoon":283.74,"night":292.04,"evening":285.9,"morning":282.36},"pressure":{"afternoon":1017.0},"wind":{"max":{"speed":7.72,"direction":210.0}}}

The precipitation for the day at this time is 0.7

The variable is being set at 0
Capture

Am I using the wrong path to get Precipitation.total?

It appears there is no “value”… ???

I would take a look at the following HTTP Action Troubleshooting guide:

Especially since you are using variables in the URL, I would check the Rule Logs to make sure that the correct URL is being called.

I would also check the raw $context.response.data to see what response body you are getting and snapshot the $context.response.status for troubleshooting to make sure you are getting a valid response code.

1 Like

So it appears this works:

https://api.openweathermap.org/data/3.0/onecall/day_summary?lat=40.1817378&lon=-80.1331118&units=imperial&date=2023-11-18&appid={MY KEY}

But this does not:

https://api.openweathermap.org/data/3.0/onecall/day_summary?lat=40.1817378&lon=-80.1331118&units=imperial&date={{$DateToday}}&appid={MY KEY}

The difference is I put today’s date directly in the URL instead of the variable $DateToday
Capture

Does something need to go before or after inserting the variable?

Did you check what the generated URL was in your Rule Logs?

I just tested with a sample variable with a request to HTTP Bin and it looks like the URL works as expected.

I can see in my rule logs that the URL is exactly what I would expect it to be.

I would make sure that the variable has exactly what you expect in it. No less. No more. In other words, you want to make sure there aren’t any spaces or any unexpected characters.

Looking back at your original post where you were asking about being able to inject a variable into a URL, it looks like the sample format string you provided has a space at the end of it, so you’ll want to make sure that doesn’t exist otherwise you’ll get a space in the resulting variable and that space will ultimately get included in the URL as well:

I guess I was so focused on the current rule that I overlooked the rule that sets the date. There was a space before the end ".

Now it works. Thank you .

1 Like

I have a rule that sets the rain in the last hour.

The variable is set using this expression:

positions = $context.response.data.current.rain.1h
isEmpty(positions) ? 0 : positions

The path is taken from JSON path finder:

I’m getting an error, and looking at the logs, it seems the “h” is missing from the expression. Is this my problem? I replaced the expression with the above, but the “h” keeps getting removed.

Capture

Variables must start with a letter (reference). I suspect that JSON Path just didn’t consider that with their design.

In order to reference a property which starts with a number, you would have to use the bracket notation.

$context.response.data.current.rain["1h"]

Pasted exactly that, but it gave me the same result:

Capture

Are you certain that the response you are receiving within the rule execution has a rain field?

I would again recommend following the troubleshooting steps in the HTTP Action Troubleshooting guide that I linked above.

If I remember correctly, the Open Weather API does not always include a rain field. In that case, you would likely want to use the same type of approach you are using with the isEmpty() check and using a fallback as needed… perhaps in multiple steps.

Well, I was… It was in the JSON path finder. Looking back at the history, we’ve not had rain in the last 2 hours, so it does not appear now. I added the [“1h”] for future, but my current fallback does not seem to handle the missing field.

positions = $context.response.data.current.rain[“1h”]
isEmpty(positions) ? 0 : positions

The rain field itself might be missing. Trying to access that field in your first line will cause the expression evaluation error. You would need to use the same type of isEmpty() check to see if that field exists or fallback to a default.

Something like the following.

current = $context.response.data.current
rain = isEmpty(current.rain) ? {} : current.rain
isEmpty(rain["1h"]) ? 0 : rain["1h"]

Or if this feels more logical to you, it’s the same result

current = $context.response.data.current
isEmpty(current.rain) ? 0 : 
  isEmpty(current.rain["1h"]) ? 0 : 
  current.rain["1h"]

It’s basically a nested IF / ELSE IF type of concept. The approach is explained at the bottom of the General Functions in Rule Expressions - SharpTools Knowledge Base article under the ‘Conditions / Ternary Expressions’ heading.

1 Like

BINGO!!!

It is missing, because of no rain currently.

I was thinking along these lines, but I was doing it backwards! It works… Much thanks… AGAIN!!

1 Like