API logic to get latest weather information - node.js

I'm writing weather API which fetches METAR and TAFS data from aviation weather stations.
Data changes once an hour.
Need to fetch latest weather information, but in my code I cannot make it to fetch it after an hour.
var express = require('express');
var router = express.Router();
const ADDS = require('adds');
var moment = require('moment');
// adds moment to the locals
router.use((req, res, next)=>{
res.locals.moment = moment;
next();
});
const avWet = Promise.all([
ADDS('metars', {
stationString: 'KCRX,KMSL,KSNH,KTUP',
hoursBeforeNow: 1,
mostRecentForEachStation: true
}),
ADDS('tafs', {
stationString: 'KTUP,KMSL',
hoursBeforeNow: 1,
mostRecentForEachStation: true
})
])
.then(results => {
const parsedData = results;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('wet_av', {
parsedData
})
})
});
module.exports = router;

You don't have to restart Your app to get data, so You don't have to use nodemon or another watcher which will restart the app too.
Simply write Your method which will get data and store it in variable
Schedule it to check for new data
Call that method to get data and push to render
const express = require('express');
const router = express.Router();
const ADDS = require('adds');
const moment = require('moment');
// adds moment to the locals
router.use((req, res, next)=>{
res.locals.moment = moment;
next();
});
let weatherInformation = null;
let weatherInformationParsedAt = 0;
async function getWeatherInformation() { // [1] method that will get data from api
const startOfHour = moment().startOf('hour').format('YYYY-MM-DD hh:')+'00';
const currentTimeString = moment().startOf('minute').format('YYYY-MM-DD hh:mm');
// if there is no data then need to parse
let needToParse = !weatherInformation;
// forcing to parse if it's 00'th minute of hour
if (startOfHour === currentTimeString &&
Date.now() - weatherInformationParsedAt > 30000
) { // if start of hour
needToParse = true;
}
// forcing to parse if data is old more than 2 mins, making sure we have fresh data
if (!needToParse &&
weatherInformation &&
Date.now() - weatherInformationParsedAt > 120000
) {
needToParse = true;
}
try {
// if need to parse so let's fetch again (that's for caching)
if (needToParse) {
const query = {
hoursBeforeNow: 1,
mostRecentForEachStation: true,
};
const results = await Promise.all([
ADDS('metars', {
...query,
stationString: 'KCRX,KMSL,KSNH,KTUP',
}),
ADDS('tafs', {
...query,
stationString: 'KTUP,KMSL',
}),
]);
weatherInformation = results;
weatherInformationParsedAt = Date.now();
}
}
catch (error) {
console.error(error);
}
return weatherInformation;
}
setInterval(getWeatherInformation, 1000); // [2] every second call method which checks for changes
router.get('/', async (req, res, next) => {
const parsedData = await getWeatherInformation(); // [3] calling method to get weather information
res.render('wet_av', {
parsedData,
});
});
module.exports = router;

Related

Post Request stuck on Postman

I am learning to build API using Node.js, Express and MongoDB. I am on early learning phase.
My code are as follow.
const app = express();
const mongojs = require("mongojs");
const { body, param, validationResult } = require("express-validator");
const db = mongojs("travel", ["records"]);
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get("/api/records", function (req, res) {
const options = req.query;
const sort = options.sort || {};
const filter = options.filter || {};
const limit = 2;
const page = parseInt(options.page) || 1;
const skip = (page - 1) * limit;
for (var i in sort) {
sort[i] = parseInt(sort[i]);
}
db.records
.find(filter)
.sort(sort)
.skip(skip)
.limit(limit, function (err, data) {
if (err) {
return res.sendStatus(500);
} else {
return res.status(200).json({
meta: {
filter,
sort,
skip,
limit,
page,
total: data.length,
},
data,
links: {
self: req.originalUrl,
},
});
}
});
});
app.post("/api/records", function (req, res) {
db.records.insert(req.body, function (err, data) {
if (err) {
return res.status(500);
}
const _id = data._id;
res.append("Location", "/api/records/" + _id);
return res.send(201).json({
meta: { _id },
data,
});
});
});
app.listen(8000, function () {
console.log("Server running at port 8000...");
});
When I try GET request on Postman, it works fine. But when I try POST request, it shows like the following. error msg image link.
Please let me know what is wrong here.
Thanks in advance

node.js Why data from post requests that is saved in a json file resets to initial empty array after restart server?

I am working with express node.js, and I am trying to save datas from post request in a json file. but for some reason when I restart the server, my data from post request was supposed to save in roomDB.json file doesnt remain instead it resets to initial empty array...
Could anyone please advice? thank you very much.
here is my code
//saving function
const fs = require("fs");
exports.save =(data, PATH) =>{
return new Promise((resolve, reject) => {
fs.writeFile(PATH, JSON.stringify(data), function(err) {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
// code in router file to make requests
const express = require("express");
const router = express.Router();
const fs = require("fs");
const rooms = ("./roomDB.json");
const { addRoom} = require("./rooms");
router.get("/", (req, res)=>{
fs.readFile("roomDB.json", (err, data)=>{
if(err) return res.status(400);
res.send(roomDB_PATH)
})
});
router.get("/:id", (req, res)=>{
res.send("connect to a room");
});
router.post("/", (req, res)=>{
let roomName = req.body;
if(!roomName.name){
res.status(404);
res.end();
return;
}
let room =addRoom(roomName.name);
res.status(201).send(room)
})
module.exports = router;
*/
const uuid = require("uuid");
let roomdatas;
const {save} = require("./save");
const roomDB_PATH = "roomDB.json";
try {
roomdatas = JSON.parse(fs.readFileSync(roomDB_PATH));
} catch (e) {
roomdatas = []
save(roomdatas, roomDB_PATH);
}
const addRoom = (roomName) => {
roomName = roomName.trim().toLowerCase();
const existingRoom = roomdatas.find((room) => room.name === roomName);
if (existingRoom) {
return { error: 'chatroom has existed' };
}
let room = {
name: roomName,
id: uuid.v4(),
messages: [],
users: [],
created: +new Date()
};
roomdatas.push(room);
save(roomdatas, roomDB_PATH);
return { room };
};
module.exports ={addRoom};
I'm assuming that you are encountering an error with the JSON.parse(fs.readFileSync(roomDB_PATH)); call. This code runs every time your server is started (when you import the file into your router file), and if it encounters an error it is resetting the file to an empty array. Try logging the error to see what is causing it. You're currently completely suppressing the error with no way to tell why it is failing.

asynchronous code not working with event listener

*Edited for clarity and to reflect changes:
Hello. I'm struggling to understand why my async functions are working just fine individually, and when chained together, but not when chained together and fired off in an event listener....
worth noting: when i try to run this without an even listener, data passes from my app, through my post route, and to my endpoint the way it should, it is then returned to my app through the correct route, etc. However, i do get an error in the console that says :
error SyntaxError: Unexpected token < in JSON at position 0
however, when i try to run my chain of async functions on the click of a dom element i don't get the above error, data is passed to my post route, i can log the object that is posted:
Object: null prototype] { zipcode: '97206', feel: 'confused' }
but then my server doesn't save any data, and my get route is never triggered, and nothing gets sent back to my app.......
i'm fairly lost.....
full server and app code below:
server:
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(express.static('public'));
//test values
let projectData = {
date: "today",
temp: "38",
feelings: "confused"
};
app.get("/", (req, res) => {
});
app.post("/postData", (req, res) => {
console.log(req.body)
projectData = {
date: req.body.date,
temp: req.body.temp,
feelings: req.body.feelings
}
console.log("post route was hit, saved:", projectData);
res.redirect("/")
});
app.get("/getData", (req, res) => {
console.log("getData route was hit, sent: ", projectData)
res.send(projectData);
})
app.listen(3000, (req, res) => {
console.log("Listening on port 3000");
});
app
let newDate = getDate();
const apiKey = "5fd7b3a253e67a551e88ff34a92b9e02";
const baseURL = "http://api.openweathermap.org/data/2.5/weather?";
// zip=${}&APPID=${}&units=metric;
const userData = {};
// returns the date //
function getDate() {
let d = new Date();
let newDate = d.getMonth() + "." + d.getDate() + "." + d.getFullYear();
return newDate;
}
//constructs string for api call, adds temp to userData object
const getData = async (apiUrl, zip, key) => {
const url = `${apiUrl}zip=${zip}&APPID=${key}&units=metric`;
const result = await fetch(url);
try {
let newData = await result.json()
// console.log(newData.main.temp)
userData.temp = newData.main.temp
}catch(error) {
console.log("error", error);
}
}
// getData(baseURL, 97206, apiKey)
// .then(result => {
// console.log(userData)
// })
//saves contents of userData Object to server
const postData = async (url, data) => {
const result = await fetch(url, {
method: "POST",
credentials: "same-origin",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(data)
});
try {
const newData = await result.json();
// console.log(newData);
return newData;
} catch (error) {
console.log("error", error);
}
};
// postData('/postData', userData);
//updates interface with projectData values from server
const updateUI = async url => {
const result = await fetch(url);
try {
const newData = await result.json();
document.getElementById("date").innerHTML = newData.date;
document.getElementById("temp").innerHTML = newData.temp;
document.getElementById("feelings").innerHTML = newData.feelings;
} catch (error) {
console.log("error", error);
}
};
// updateUI("/getData")
// THIS WORKS
userData.date = newDate;
userData.feelings = document.getElementById("feel").value;
const zipCode = document.getElementById("zipcode").value;
getData(baseURL, 97206, apiKey).then(result => {
postData("/postData", userData).then(result => {
updateUI("/getData");
});
});
// THIS DOESNT WORK
// document.getElementById("btn").addEventListener("click", e => {
// userData.date = newDate;
// userData.feelings = document.getElementById("feel").value;
// const zipCode = document.getElementById("zipcode").value;
// getData(baseURL, zipCode, apiKey).then(result => {
// postData("/postData", userData).then(result => {
// updateUI("/getData");
// });
// });
// });
EDIT:
I realized that the information that was being passed through the post route when my async functions are fired off by an event listener was actually just the form input element values, rather than the contents of the fetch/post request. after i removed the name attributes from the form inputs, i'm getting no data at all hitting my post route......yet the corosponding function works fine with not in the event listener.
I'm stumped.
well, the syntax error was solved by using .text() instead of .json() on the results of my post request.
adding e.preventDefault() as the first line of my event listener callback fixed the event listener, and now everything is working as it should.

expressjs returning controller object to res.send

I have a controller that makes an api call (few seconds delay) and then returns a JSON object that I want to send and appear on my view page. At the moment I am able to return the object and successfully load the route, but the object is not appearing on my browser page (status code: 200) and I'm not sure what I might be missing. Provided below is my route and controller.
Controller:
var express = require('express');
var apiRouter = express.Router();
var googleAnalytics = require('../google-analytics');
const { checkToken } = require("./components/token-validator");
apiRouter.use(checkToken);
apiRouter.get('/ga', function(req, res){
res.send(googleAnalytics())
});
module.exports = apiRouter;
Controller (googleAnalytics):
module.exports = () => {
console.log("google-analytics.js")
const {google} = require('googleapis');
const analyticsreporting = google.analyticsreporting('v4');
const view_id = '*view-id(';
... // resource: req information
analyticsreporting.reports.batchGet({
resource: req
}, (err, result) => {
if(err){
if(err.errors){
console.log(err.errors[0].message)
} else {
console.log(err)
}
} else {
return result.data;
}
//console.log("BREAK IN CONSOLE")
//console.log(err, result)
})
}
Object E.g.:
{"reports":[{"columnHeader":{"dimensions":["ga:sourceMedium"],"metricHeader":{"metricHeaderEntries":
...
]}}
You are not returning anything from the google-analytics.js. You need to make the function return a promise or use callback. analyticsreporting.reports.batchGet returns a promise so it is pretty easy to do that.
module.exports = () => {
console.log("google-analytics.js")
const {google} = require('googleapis');
const analyticsreporting = google.analyticsreporting('v4');
const view_id = '*view-id(';
... // resource: req information
return analyticsreporting.reports.batchGet({
resource: req
});
}
Now, in your /ga route, you can use async-await:
apiRouter.get('/ga', async function(req, res){
res.send(await googleAnalytics())
});

Why promise.resolve wait forever in this case?

I am a nodejs's newbie. I'm testing a promise and have an issue.
Here's my issue.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get('/', async function(req,res){
console.log(222);
res.send("Hello!!!");
let check;
try {
console.log(3333);
check = await test();
console.log(4444);
} catch (err) {
console.log("Error : ", err);
}
console.log(111, check);
});
function test () {
return new Promise (resolve => {
console.log(5555);
app.get('/test', function(req, res) {
count = count + 1;
res.send(count.toString());
resolve("hahahaha");
})
})
}
app.listen(9000, function(){
console.log("hehehehe");
});
In a get 'http://localhost:9000' callback, I wait for 'http://localhost:9000/test' result to do something. The thing is, it's working fine for the first time. But since the 2nd, the promise.resolve() function doesn't work.
Here is my first time log:
hehehehe
222
3333
5555
4444
111 'hahahaha'
And here is my second time log :
222
3333
5555
the promise.resovle() doesn't work. It's waiting forever and I don't understand.
EDIT : Here is the solution for using EventEmitter to do signup and smsVerifyCode after modified by the help of Mr. #Aritra Chakraborty
var express = require('express');
var userControler = require('../Controler/user');
var router = express.Router();
var utils = require('../Helper/Utils');
var user_model = require('../Models/user');
const TIMEOUT_VERIFY = 300000;
const CODE_EXPIRED = 0;
const CODE_VALID = 1;
const CODE_INVALID = 2;
const CONTACT_EXISTED = 3;
const DATABASE_ABUSED = 4;
const events = require('events');
const emitter = new events.EventEmitter();
function timeout_verify_sms_emitter (time) {
setTimeout(() => {
emitter.emit('timeout_sms');
}, time);
}
function verify_code(codeGen) {
return new Promise((resolve, reject)=>{
emitter.on("verifySMS", (data)=>{
if (data === codeGen) {
resolve(CODE_VALID);
}
else {
resolve(CODE_INVALID);
}
})
emitter.on('timeout_sms', () =>{
resolve(CODE_EXPIRED);
});
})
}
router.get('/',function(req,res){
res.send("Welcome to the Earth!!!");
})
router.post('/signup', async function(req,res){
let verifyCode;
let checkContact;
let codeGen = utils.generateCode();
try {
checkContact = await user_model.checkContact(userData.contact);
if (checkContact === true) {
res.send(CONTACT_EXISTED);
}
else {
//call send sms to contact function here
//exam : sendSMS(contact)
//
timeout_verify_sms_emitter(TIMEOUT_VERIFY);
verifyCode = await verify_code(codeGen);
}
}
catch (err) {
console.log("Error : ", err);
}
if (verifyCode === CODE_EXPIRED) {
res.send(CODE_EXPIRED);
}
else if (verifyCode === CODE_VALID) {
var result = userControler.processUserData(req.body);
if (result) {
res.send(CODE_VALID);
}
else {
res.send(DATABASE_ABUSED);
}
}
else {
res.send (CODE_INVALID);
}
})
router.post('/signup/verifySMS', function(req, res){
emitter.emit("verifySMS", req.body.smsCode);
})
module.exports = router;
According to the above code:
Whenever you do a get request to / you are CREATING a /test path.
So, the first time it works because /test path has one handler.
Second or more time it doesn't works because,
The /test route has multiple handler now.
How express works is, routes get executed according to their declaration time. (Think middlewares)
Now, Second time the /test will have 2 handlers. And when you hit /test the first handler runs. And as this is not a middlware it doesn't go to the next handler. Now, the first handler has a different resolve function then the second one. So the second resolve function doesn't run at all.(Think closure)
For what are you trying to do most web implementations use long polling. Because if you wait too long for the second route it will throw a timeout error. Means you periodically hit an api to get the status of something. Means you create 3 routes.
A main route, like /signup
A second route like /sendsms
A third route where you send a particual identifier and it returns some positve/negative value. like /sendsms/check, where you might pass the phone number.
Otherwise if you don't care about timeouts you can use EventEmitter inside the /test route.
EDIT1:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
const events = require('events');
const emitter = new events.EventEmitter();
let count = 0;
app.get('/', async function (req, res) {
console.log(222);
res.send("Hello!!!");
let check;
try {
console.log(3333);
check = await test();
console.log(4444);
}
catch (err) {
console.log("Error : ", err);
}
console.log(111, check);
});
app.get('/test', function (req, res) {
count = count + 1;
emitter.emit("test",count.toString());
res.send(count.toString());
})
function test(){
return new Promise((res)=>{
emitter.on("test", (data)=>{
res(data);
})
})
}
app.listen(9000, function () {
console.log("hehehehe");
});
EDIT2:
Regarding the solution, you need to handle the timeout differently. Let's say your timeout is 3sec. And the SMS route took 100sec to get a response or maybe it didn't even got a response. Then your function will be stuck there.
function test(sendSMSTime) {
return new Promise((res, rej) => {
emitter.on("test", (data) => {
.
.
res(data);
})
emitter.on('timeout', rej);//On timeout it will run.
})
}
function timeoutEmitter(timeout) {
setTimeout(() => {
emitter.emit('timeout');
}, timeout)
}
app.post('/signup', async function (req, res) {
try {
timeoutEmitter(3000);
.
.
}catch{
}
});

Resources