From 6ee9a66f40b4cca83222a369017450edc880673c Mon Sep 17 00:00:00 2001 From: sam detweiler Date: Mon, 26 May 2025 07:24:44 -0500 Subject: [PATCH 1/3] add error handling to weather fetch functions, including cors --- CHANGELOG.md | 1 + js/server_functions.js | 20 ++++++++++++-------- modules/default/utils.js | 26 ++++++++++++++++---------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 637f220143..30a80d3cb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ planned for 2025-07-01 - [calendar] fix fullday event rrule until with timezone offset (#3781) - [feat] Add rule `no-undef` in config file validation to fix #3785 (#3786) - [fonts] Fix `roboto.css` to avoid error message `Unknown descriptor 'var(' in @font-face rule.` in firefox console (#3787) +- [weather] add error handling to fetch functions including cors ### Updated diff --git a/js/server_functions.js b/js/server_functions.js index 07c6df534c..5ac297387d 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -41,25 +41,29 @@ async function cors (req, res) { url = `invalid url: ${req.url}`; Log.error(url); res.send(url); - } else { - url = match[1]; - - const headersToSend = getHeadersToSend(req.url); - const expectedReceivedHeaders = geExpectedReceivedHeaders(req.url); + return; + } + url = match[1]; - Log.log(`cors url: ${url}`); - const response = await fetch(url, { headers: headersToSend }); + const headersToSend = getHeadersToSend(req.url); + const expectedReceivedHeaders = geExpectedReceivedHeaders(req.url); + Log.log(`cors url: ${url}`); + const response = await fetch(url, { headers: headersToSend }); + if (response.ok) { for (const header of expectedReceivedHeaders) { const headerValue = response.headers.get(header); if (header) res.set(header, headerValue); } const data = await response.text(); res.send(data); + } else { + res.status(response.status).json({ message: response.statusText }); } + } catch (error) { Log.error(error); - res.send(error); + res.status(500).json({ message: error.message }); } } diff --git a/modules/default/utils.js b/modules/default/utils.js index 2d6e43ab10..d801554444 100644 --- a/modules/default/utils.js +++ b/modules/default/utils.js @@ -17,20 +17,26 @@ async function performWebRequest (url, type = "json", useCorsProxy = false, requ requestUrl = url; request.headers = getHeadersToSend(requestHeaders); } - const response = await fetch(requestUrl, request); - const data = await response.text(); - if (type === "xml") { - return new DOMParser().parseFromString(data, "text/html"); - } else { - if (!data || !data.length > 0) return undefined; + let response = await fetch(requestUrl, request); + if (response.ok) { + const data = await response.text(); + + if (type === "xml") { + return new DOMParser().parseFromString(data, "text/html"); + } else { + if (!data || !data.length > 0) return "null"; //undefined; - const dataResponse = JSON.parse(data); - if (!dataResponse.headers) { - dataResponse.headers = getHeadersFromResponse(expectedResponseHeaders, response); + const dataResponse = JSON.parse(data); + if (!dataResponse.headers) { + dataResponse.headers = getHeadersFromResponse(expectedResponseHeaders, response); + } + return dataResponse; } - return dataResponse; + } else { + throw new Error(`Response status: ${response.status}`); } + } /** From b5487c8beca937cce67bb173aef11a4ee1e1fb97 Mon Sep 17 00:00:00 2001 From: sam detweiler Date: Mon, 26 May 2025 07:52:58 -0500 Subject: [PATCH 2/3] fix let vs const --- modules/default/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/utils.js b/modules/default/utils.js index d801554444..7381505117 100644 --- a/modules/default/utils.js +++ b/modules/default/utils.js @@ -18,7 +18,7 @@ async function performWebRequest (url, type = "json", useCorsProxy = false, requ request.headers = getHeadersToSend(requestHeaders); } - let response = await fetch(requestUrl, request); + const response = await fetch(requestUrl, request); if (response.ok) { const data = await response.text(); From c0a84c5e01018c2270a6fd649d3da076435c7a1e Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Mon, 9 Jun 2025 00:47:26 +0200 Subject: [PATCH 3/3] Refactor and get tests work again --- CHANGELOG.md | 2 +- js/server_functions.js | 39 +++++++------- modules/default/utils.js | 31 ++++++----- .../weather/providers/pirateweather.js | 54 +++++++++---------- tests/unit/functions/server_functions_spec.js | 3 +- 5 files changed, 65 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30a80d3cb1..0ead3361b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,7 @@ planned for 2025-07-01 - [calendar] fix fullday event rrule until with timezone offset (#3781) - [feat] Add rule `no-undef` in config file validation to fix #3785 (#3786) - [fonts] Fix `roboto.css` to avoid error message `Unknown descriptor 'var(' in @font-face rule.` in firefox console (#3787) -- [weather] add error handling to fetch functions including cors +- [weather] Add error handling to fetch functions including cors (#3791) ### Updated diff --git a/js/server_functions.js b/js/server_functions.js index 5ac297387d..72520cad68 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -41,29 +41,28 @@ async function cors (req, res) { url = `invalid url: ${req.url}`; Log.error(url); res.send(url); - return; - } - url = match[1]; - - const headersToSend = getHeadersToSend(req.url); - const expectedReceivedHeaders = geExpectedReceivedHeaders(req.url); - Log.log(`cors url: ${url}`); - - const response = await fetch(url, { headers: headersToSend }); - if (response.ok) { - for (const header of expectedReceivedHeaders) { - const headerValue = response.headers.get(header); - if (header) res.set(header, headerValue); - } - const data = await response.text(); - res.send(data); } else { - res.status(response.status).json({ message: response.statusText }); + url = match[1]; + + const headersToSend = getHeadersToSend(req.url); + const expectedReceivedHeaders = geExpectedReceivedHeaders(req.url); + Log.log(`cors url: ${url}`); + + const response = await fetch(url, { headers: headersToSend }); + if (response.ok) { + for (const header of expectedReceivedHeaders) { + const headerValue = response.headers.get(header); + if (header) res.set(header, headerValue); + } + const data = await response.text(); + res.send(data); + } else { + throw new Error(`Response status: ${response.status}`); + } } - } catch (error) { - Log.error(error); - res.status(500).json({ message: error.message }); + Log.error(`Error in CORS request: ${error}`); + res.send(error); } } diff --git a/modules/default/utils.js b/modules/default/utils.js index 7381505117..cc9b7a1813 100644 --- a/modules/default/utils.js +++ b/modules/default/utils.js @@ -18,25 +18,28 @@ async function performWebRequest (url, type = "json", useCorsProxy = false, requ request.headers = getHeadersToSend(requestHeaders); } - const response = await fetch(requestUrl, request); - if (response.ok) { - const data = await response.text(); + try { + const response = await fetch(requestUrl, request); + if (response.ok) { + const data = await response.text(); - if (type === "xml") { - return new DOMParser().parseFromString(data, "text/html"); - } else { - if (!data || !data.length > 0) return "null"; //undefined; + if (type === "xml") { + return new DOMParser().parseFromString(data, "text/html"); + } else { + if (!data || !data.length > 0) return undefined; - const dataResponse = JSON.parse(data); - if (!dataResponse.headers) { - dataResponse.headers = getHeadersFromResponse(expectedResponseHeaders, response); + const dataResponse = JSON.parse(data); + if (!dataResponse.headers) { + dataResponse.headers = getHeadersFromResponse(expectedResponseHeaders, response); + } + return dataResponse; } - return dataResponse; + } else { + throw new Error(`Response status: ${response.status}`); } - } else { - throw new Error(`Response status: ${response.status}`); + } catch (error) { + Log.error(`Error fetching data from ${url}: ${error}`); } - } /** diff --git a/modules/default/weather/providers/pirateweather.js b/modules/default/weather/providers/pirateweather.js index 969912f4e1..48a909c692 100644 --- a/modules/default/weather/providers/pirateweather.js +++ b/modules/default/weather/providers/pirateweather.js @@ -22,38 +22,36 @@ WeatherProvider.register("pirateweather", { lon: 0 }, - fetchCurrentWeather () { - this.fetchData(this.getUrl()) - .then((data) => { - if (!data || !data.currently || typeof data.currently.temperature === "undefined") { - // No usable data? - return; - } + async fetchCurrentWeather () { + try { + const data = await this.fetchData(this.getUrl()); + if (!data || !data.currently || typeof data.currently.temperature === "undefined") { + throw new Error("No usable data received from Pirate Weather API."); + } - const currentWeather = this.generateWeatherDayFromCurrentWeather(data); - this.setCurrentWeather(currentWeather); - }) - .catch(function (request) { - Log.error("Could not load data ... ", request); - }) - .finally(() => this.updateAvailable()); + const currentWeather = this.generateWeatherDayFromCurrentWeather(data); + this.setCurrentWeather(currentWeather); + } catch (error) { + Log.error("Could not load data ... ", error); + } finally { + this.updateAvailable(); + } }, - fetchWeatherForecast () { - this.fetchData(this.getUrl()) - .then((data) => { - if (!data || !data.daily || !data.daily.data.length) { - // No usable data? - return; - } + async fetchWeatherForecast () { + try { + const data = await this.fetchData(this.getUrl()); + if (!data || !data.daily || !data.daily.data.length) { + throw new Error("No usable data received from Pirate Weather API."); + } - const forecast = this.generateWeatherObjectsFromForecast(data.daily.data); - this.setWeatherForecast(forecast); - }) - .catch(function (request) { - Log.error("Could not load data ... ", request); - }) - .finally(() => this.updateAvailable()); + const forecast = this.generateWeatherObjectsFromForecast(data.daily.data); + this.setWeatherForecast(forecast); + } catch (error) { + Log.error("Could not load data ... ", error); + } finally { + this.updateAvailable(); + } }, // Create a URL from the config and base URL. diff --git a/tests/unit/functions/server_functions_spec.js b/tests/unit/functions/server_functions_spec.js index d394d055c3..575cc4a822 100644 --- a/tests/unit/functions/server_functions_spec.js +++ b/tests/unit/functions/server_functions_spec.js @@ -17,7 +17,8 @@ describe("server_functions tests", () => { headers: { get: fetchResponseHeadersGet }, - text: fetchResponseHeadersText + text: fetchResponseHeadersText, + ok: true }; fetch = jest.fn();