expressjs returning controller object to res.send - node.js

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())
});

Related

req is "undefined" in one middleware and not in another

I am trying to use sharp in my MERN application, I sent a request from my frontend and it is undefined in my sharp middleware but if I get rid of the sharp middleware the req is defined later on. If I log the request in createCountry, the body is defined, if I log it in convertToWebP, it is not.
the route is the one that says "/new" below:
const express = require("express");
const router = express.Router();
const { storage } = require("../imageupload/cloudinary.js");
const multer = require("multer");
const {
getCountry,
createCountry,
getCountries,
updateCountry,
deleteCountry,
getAllCountries,
} = require("../controllers/country.js");
const {convertToWebP} = require('../middlewares/toWebP')
const { isLoggedIn, authorizeCountry, validateCountry } = require("../middlewares/auth");
const catchAsync = require("../utils/catchAsync");
const ExpressError = require("../utils/ExpressError");
const upload = multer({ storage: storage });
router.get("/", getCountries);
router.get('/getAll', getAllCountries);
router.post("/new", isLoggedIn, converToWebP, upload.array("images"), createCountry);
router.get("/:countryId", getCountry);
router.patch("/:countryId", validateCountry, authorizeCountry, upload.array("images", 8), updateCountry);
router.delete("/:countryId", authorizeCountry, deleteCountry);
module.exports = router;
the code for create country is here:
exports.createCountry = async (req, res) => {
const { name, description, tags, location, cjLink } = req.body;
const creator = req.user._id;
const images = req.files.map((file) => {
return { image: file.path, publicId: file.filename };
});
try {
const geoData = await geocoder
.forwardGeocode({
query: req.body.location,
limit: 1,
})
.send();
const geometry = geoData.body.features[0].geometry;
const country = new Country({
name,
description,
tags,
creator,
location, //: //geometry
geometry,
url: '',
cjLink: cjLink,
});
const overall = new Overall({
name,
description,
tags,
creator,
location, //: //geometry
geometry,
url: '',
cjLink: cjLink,
});
country.images.push(...images);
country.headerImage.push(...images);
const data = await country.save();
overall.url = `/country/${data._id}`
data.url = `/country/${data._id}`
overall.save();
data.save();
return res.status(201).json(data);
} catch (error) {
return console.log("error during create country", error);
}
};
And lastly the code for the convertToWebP is here:
const sharp = require("sharp");
const { cloudinary } = require("../imageupload/cloudinary");
exports.convertToWebP = async (req, res, next) => {
try {
req.files = await Promise.all(req.files.map(async (file) => {
const buffer = await sharp(file.buffer)
.toFormat('webp')
.toBuffer();
return { ...file, buffer, originalname: `${file.originalname}.webp` };
}));
next();
} catch (error) {
res.status(500).json({ message: error.message });
}
};
Any help is appreciated! I tried console.log as described above, I tried to change the order of the middleware and that does not work either, and I tried logging the req.body directly from the route and it came up as an empty object
You cannot acces req.files before you use multer middleware
You have to reorder
router.post("/new", isLoggedIn, upload.array("images"), converToWebP, createCountry);

API logic to get latest weather information

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;

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.

console.log not fired when promise is executed

I have a js file in which i export a promise and i call it in another file.
I dnt understand why the console logs are not fired when i call the promise,
maybe i dnt fully understand how promises work or maybe sth is wrong with the way i call the promise
pub.js
var config = require('../config');
var q = 'tasks';
var open = require('amqplib').connect('amqp://'+ config.rabbitmq.url);
module.exports = open.then(function(conn) {
return conn.createChannel();
}).then(function(ch) {
return ch.assertQueue(q).then(function(ok) {
console.log('inside publisher')
const r = ch.sendToQueue(q, Buffer.from('something to do'));
console.log('r',r)
return r
});
}).catch(console.warn);
index.js (where i call the promise)
var express = require('express');
var router = express.Router();
var publisher = require('../connectors/pub');
var rabbitPromise = () => (
new Promise((resolve,reject)=>{
publisher
.then(res=>{
console.log('-----------------------')
console.log('publishing now',res)
resolve(res)
})
})
);
/* GET home page. */
router.get('/', async(req, res, next) => {
const result_pub = await rabbitPromise()
res.send('ok')
});
I expected to see the console.log('inside publisher') but i don't see it i only get console.log('-----------------------') and console.log('publishing now',res),
the chaining in pub.js is not right. In order to call the promise, it would be something more like this :
module.exports = open
.then(function(conn) {
return conn.createChannel();
})
.then(function(ch) {
return ch.assertQueue(q);
})
.then(function(ok) {
console.log('inside publisher')
const r = ch.sendToQueue(q, Buffer.from('something to do'));
console.log('r',r)
return r
})
.catch(console.warn);

The request won't go through api path

I'm making a post request with jquery to '/get_access_token' url. but it is not going through. In postman the request is stuck in 'Sending'. Below I'm adding the code.
app.js
const myRouter = require('./src/routes/myRouter ');
app.use('/get_access_token', myRouter );
myRouter,js
//this is inside myRouter
const express = require('express');
const myRouter= express.Router();
const myController = require('../controllers/myController');
function router() {
debug('inside router');
const { getAccessToken } = myController();
debug(getAccessToken);
//from here it is not going down
myRouter.route('/get_access_token').post((request) => {
debug('inside api call');
const result = getAccessToken(request);
});
}
module.exports = router;
myController.js
const client = require('path to client');
function myController() {
function getAccessToken(request) {
debug('inside getAccessToken');
const PUBLIC_TOKEN = request.body.public_token;
Promise((resolve, reject) => {
client.exchangePublicToken(PUBLIC_TOKEN, (error, tokenResponse) => {
if (error != null) {
reject(new Error('Could not get access token'));
}
const ACCESS_TOKEN = tokenResponse.access_token;
const ITEM_ID = tokenResponse.item_id;
debug(ACCESS_TOKEN);
debug(ITEM_ID);
resolve('Access Token was acquired succesfully');
});
});
}
return {
getAccessToken
};
}
module.exports = myController;
jquery request, only the portion when there is a public token
onSuccess: function(public_token) {
debugger;
$.post('/get_access_token', {
public_token: public_token
}, function() {
$('#container').fadeOut('fast', function() {
$('#intro').hide();
$('#app, #steps').fadeIn('slow');
});
});
}
This is the issue
module.exports = router;
Router is the function, not the router actually, it cannot work.
It can theoretically work if you exports the myRouter, but you have to define it properly.
I suggest to find some "express boilerplate" on internet, make it work and then just update that code to your needs

Resources