diff --git a/index.js b/index.js index 196b113..1c95378 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ const express = require('express') const weather = require('./src/weatherAPI.js') -const {requestCityFromIP, requestCoordsFromIP} = require('./src/geoipAPI.js') +const {geolocateFromIP} = require('./src/geoipAPI.js') const anonymizeip = require('./src/anonymizeip.js') var path = require('path'); @@ -28,31 +28,47 @@ api.get('/', (req, res) => { ipAddr: anonymizeip(clientIP), } - requestCityFromIP(clientIP).then((coords) => { - console.log('Coords obj:', coords) + const weatherResp = geolocateFromIP(clientIP).then((coords) => { + // If the geolocation is successful, format the name of the returned location, + // then call the weather API with the coordinates and timezone. - if ("regionName" in coords && "city" in coords && "country" in coords) { - renderValues.locationName = `${coords.city}, ${coords.regionName}, ${coords.country}` - } else if ("country" in coords) { - if ("city" in coords) { - renderValues.locationName = `${coords.city}, ${coords.country}` - } else if ("region" in coords) { - renderValues.locationName = `${coords.regionName}, ${coords.country}` + renderValues.locationName = coords.locationName + return weather(coords.lat, coords.lon, coords.timezone) + }).catch(() => { + // If the geolocation fails, default to Toronto, Ontario, Canada, then call + // the weather API with the coordinates and timezone. + + renderValues.locationName = "Toronto, Ontario, Canada" + return weather("43.7", "-79.42", "America/Toronto") + }) + + weatherResp.then((weatherData) => { + // Once the weather API call is successful, render the index page with the + // template values specified in `renderValues`. + + renderValues.forecast = weatherData + return res.render('index', renderValues, function (err, html) { + if (err) { + console.error("Error rendering index page:", err) + return res.status(500).send('An error occurred while rendering the page.') } else { - renderValues.locationName = coords.country + return res.send(html) } - } else if ("city" in coords) { - renderValues.locationName = coords.city - } else { - renderValues.locationName = coords.regionName - } - - // By default, display the weather in Toronto. - return weather("43.7001", "-79.4163", "America/Toronto") - }).then((weatherData) => { - // renderValues.forecast = JSON.stringify(weatherData) - renderValues.forecast = weatherData - res.render('index', renderValues) + }) + }).catch((e) => { + // If the weather API call fails, render the index page with the template + // and the limited values that are available. + + console.error("Error in main route:", e) + res.render('index', renderValues, function (err, html) { + if (err) { + console.error("Error rendering index page:", err) + return res.status(500).send('An error occurred while rendering the page.') + } else { + return res.send(html) + } + + }) }) }) @@ -61,19 +77,22 @@ api.get('/geolocate', (req, res) => { // will send a request to `/geolocate` to get the estimated coordinates // of the client's IP address. This will then return the coordinates to the // client, which will use them to call the weather API as it normally would. - geoip(req.ip).then((coords) => { - res.json(coords) - }) + geolocateFromIP(req.ip) + .then(coords => res.json(coords)) + .catch(e => res.json({status: 'error', code: 500, message: e.message})) }) api.get('/weather', (req, res) => { const queryParams = req.query if (!queryParams.lat || !queryParams.lon || !queryParams.timezone) { res.status(400).send('Missing query parameters. All of the following are required: lat, lon, timezone') + return } weather(queryParams.lat, queryParams.lon, queryParams.timezone).then((weatherData) => { res.json(weatherData) + }).catch((e) => { + res.json({status: 'error', code: 500, message: e.message}) }) }) diff --git a/src/geoipAPI.js b/src/geoipAPI.js index bf69bfd..dd48de9 100644 --- a/src/geoipAPI.js +++ b/src/geoipAPI.js @@ -29,6 +29,16 @@ function buildAPIRequest(ipAddr, fieldsVal) { } +const defaultCoords = { + status: 'success', + country: 'Canada', + regionName: 'Ontario', + city: 'Toronto', + lat: '43.7', + lon: '-79.42', + timezone: 'America/Toronto', +} + function apiRequest(url) { return new Promise((resolve, reject) => { @@ -49,6 +59,26 @@ function apiRequest(url) { res.on('end', () => { try { coordsResponse = JSON.parse(responseData) + // console.log("coordsResponse: ", coordsResponse) + + let locationName = '' + if ("regionName" in coordsResponse && "city" in coordsResponse && "country" in coordsResponse) { + locationName = `${coordsResponse.city}, ${coordsResponse.regionName}, ${coordsResponse.country}` + } else if ("country" in coordsResponse) { + if ("city" in coordsResponse) { + locationName = `${coordsResponse.city}, ${coordsResponse.country}` + } else if ("regionName" in coordsResponse) { + locationName = `${coordsResponse.regionName}, ${coordsResponse.country}` + } else { + locationName = coordsResponse.country + } + } else if ("city" in coordsResponse) { + locationName = coordsResponse.city + } else { + locationName = coordsResponse.regionName + } + + coordsResponse.locationName = locationName // Because this sample app is used in live demos, we want to // anonymize the coordinates returned to the client side. @@ -58,13 +88,17 @@ function apiRequest(url) { } if (coordsResponse.status !== 'success') { - throw new Error('API request to `ip-api.com` failed.') + // If our query to the geolocation API endpoint fails, + // return the default coordinates object, which has the + // coordinates and timezone for Toronto, Ontario, Canada. + console.error('API request to `ip-api.com` did not succeed. Rejecting with default coordinates object (Toronto).') + reject(defaultCoords) } else { resolve(coordsResponse) } } catch (e) { console.error(e.message) - reject(e) + reject(defaultCoords) } }) }) @@ -78,7 +112,7 @@ function apiRequest(url) { }) } -function requestCoordsFromIP(ipAddr) { +function geolocateFromIP(ipAddr) { // Validate input and throw an error if the input string isn't a valid IP address. if (!ipAddrRegex.test(ipAddr)) { @@ -89,20 +123,8 @@ function requestCoordsFromIP(ipAddr) { return apiRequest(url) } -function requestCityFromIP(ipAddr) { - - // Validate input and throw an error if the input string isn't a valid IP address. - if (!ipAddrRegex.test(ipAddr)) { - throw new Error('Invalid IP address format') - } - - const url = buildAPIRequest(ipAddr, 'status,country,regionName,city') - return apiRequest(url) -} - module.exports = { - requestCityFromIP, - requestCoordsFromIP, + geolocateFromIP, } diff --git a/src/weatherAPI.js b/src/weatherAPI.js index 24b321b..60f9e3b 100644 --- a/src/weatherAPI.js +++ b/src/weatherAPI.js @@ -145,7 +145,7 @@ function generateForecast(weatherData) { dailyForecasts[day] = singleDayForecast }) - console.log(dailyForecasts) + // console.log(dailyForecasts) return dailyForecasts } @@ -182,8 +182,8 @@ function getWeather(lat, lon, timezone) { timezone: timezone }) - console.log('------------------------------\nQuery parameters:') - console.log(queryParams) + // console.log('------------------------------\nQuery parameters:') + // console.log(queryParams) const queryString = Object.keys(queryParams).map(key => key + '=' + queryParams[key]).join('&') diff --git a/views/currentConditions.pug b/views/currentConditions.pug index 37316ef..b814928 100644 --- a/views/currentConditions.pug +++ b/views/currentConditions.pug @@ -2,7 +2,7 @@ h3 Weather Forecast button(id="geolocate") Get Local Forecast p(id="coords") #forecast - if forecast.current + if forecast && forecast.current if forecast.current.temperature_2m #currentTemperature span(id="currentTempVal") #{forecast.current.temperature_2m[0]}