Help

Re: Hitting a roadblock with an API call

Solved
Jump to Solution
952 4
cancel
Showing results for 
Search instead for 
Did you mean: 

I’m trying to add more intelligent time support to one of my bases, so I went looking for a free time API that I could query, and I found this:


It looked like it would fit the bill, so I built a quick test in the Scripting app. However, I hit a CORS-related error, so I shifted testing to a script action in an automation. While I’m no longer getting an error, I’m also not getting the response I’m expecting based on the examples on the above site. Here’s my simple test based on the first example shown on the homepage:
let result = await fetch("http://worldtimeapi.org/api/timezone")
console.log(result)

This is supposed to return a full list of timezones, but this is what the console shows:

Screen Shot 2020-11-01 at 8.41.16 AM

I’m still relatively new to calling APIs, so it’s possible I’m missing something basic, but I’m not sure what it is.

1 Solution

Accepted Solutions
Bill_French
17 - Neptune
17 - Neptune

Neither am I but I think it’s this… response.json() I think is what you want, otherwise, response will simply provide the response header by default.

let response = await fetch(url);

if (response.ok) { // if HTTP-status is 200-299
  // get the response body (the method explained below)
  let json = await response.json();
} else {
  console.log("HTTP-Error: " + response.status);
}

UPDATE (10 minutes later):

Now I’m absolutely certain you were missing something basic. :winking_face: I believe you’re looking for this:

image

And this is possible both in Script Actions and Script block despite the CORS issue. Here’s the remedy:

//
// http get timezones (from https://worldtimeapi.org)
//
output.markdown('## HTTP Timezones Test');

// set the get url
let url = 'https://worldtimeapi.org/api/timezone';

// fetch the data
let oResponse = await fetch(url);

if (oResponse.ok) {                      // if HTTP-status is 200-299
  let oTimeZones = await oResponse.json();
  output.inspect(oTimeZones);
} else {
  output.inspect("HTTP-Error: " + oResponse.status);
}

See Solution in Thread

5 Replies 5
Bill_French
17 - Neptune
17 - Neptune

Neither am I but I think it’s this… response.json() I think is what you want, otherwise, response will simply provide the response header by default.

let response = await fetch(url);

if (response.ok) { // if HTTP-status is 200-299
  // get the response body (the method explained below)
  let json = await response.json();
} else {
  console.log("HTTP-Error: " + response.status);
}

UPDATE (10 minutes later):

Now I’m absolutely certain you were missing something basic. :winking_face: I believe you’re looking for this:

image

And this is possible both in Script Actions and Script block despite the CORS issue. Here’s the remedy:

//
// http get timezones (from https://worldtimeapi.org)
//
output.markdown('## HTTP Timezones Test');

// set the get url
let url = 'https://worldtimeapi.org/api/timezone';

// fetch the data
let oResponse = await fetch(url);

if (oResponse.ok) {                      // if HTTP-status is 200-299
  let oTimeZones = await oResponse.json();
  output.inspect(oTimeZones);
} else {
  output.inspect("HTTP-Error: " + oResponse.status);
}

Thanks, Bill! So far most of my use of “fetch” has been to call webhooks, and I haven’t had to process a response. However, I clearly didn’t remember the one time I set up an automation to call the Google API. If I had, I would have found this solution much sooner

As for the CORS issue, your example indicates that it appears to be a difference (at least in this case) between HTTP vs HTTPS. The documentation for this API only says the following re: the latter:

Some IoT devices struggle with HTTPS connections, and the data we return isn’t sensitive, so standard HTTP requests to the API are the default.

However, since we agree that encrypting the web is a good thing, we’ve recently added experimental HTTPS support. Please note that we’re actively monitoring and should we find any performance issues HTTPS support will be withdrawn.

While I’ll probably end up using this in an automation, it’s good to know that it’ll also work in the Scripting app.

Yes, I took the liberty of using HTTPS because I have seen cases where lacking encryption will cause CORS issues, but in this specific API, this doesn’t seem to be the case - it works with both.

I believe the CORS condition is triggered when trying to assert specific headers. Since this is a simple API request, authentication and content assertions (in headers) are not needed and any attempt to call fetch() with such assertions awake the CORS beast. I believe this is why your simple fetch() call in a Script Action immediately showed the response which did [in fact] come back as a 200OK. Armed with that, I knew your code was fine and CORS was not an issue - it just needed to be coaxed a little more to get at the data response.

But CORS was an issue. If you refer to my initial note, I first tried using the Scripting app with the recommended HTTP request. That’s when I hit CORS (big red error message all about it), which led me to test in an automation’s scripting action, where I knew that wouldn’t be an issue. Only then did I get the 200 OK response. If I try your code with “http” instead of “https” in a Scripting app, the CORS error is there.

Hmmm… indeed. I thought I tested with both but it seems I changed only the comment line. So, back to my original fear - that HTTP awakens the CORS beast and HTTPS is required to dodge this issue.