NodeJS return value in axios get [duplicate] - javascript

This question already has answers here:
Return from a promise then()
(8 answers)
Closed 9 months ago.
I have this class written in javascript but I have difficulty in obtaining the result from the axios request, below my situation to better explain the problem:
i have a file called vtiger.js in the classes directory in the project root
vtiger.js
const axios = require('axios');
var md5 = require('md5');
var qs = require('qs');
const https = require('https');
class vTiger {
constructor() {
this.url = process.env.VTIGER_URL;
this.username = process.env.VTIGER_USERNAME;
this.password = process.env.VTIGER_PASSWORD;
}
async getchallengeTokenVtiger() {
var token;
var tokenmd5 = false;
var url = this.url + 'webservice.php?operation=getchallenge&username=' + this.username;
axios.get(url,
{
headers: {
"content-type": "application/x-www-form-urlencoded"
},
httpsAgent: new https.Agent(
{
rejectUnauthorized: false
})
}).then(response => {
if (response.data.success) {
token = response.data.result.token;
tokenmd5 = md5(token + this.password);
return tokenmd5;
}
});
}
}
module.exports = vTiger
then I have a file called api.js in the controllers folder with this content:
const http = require('http');
const axios = require('axios');
var qs = require('qs');
const vTiger = require('../classes/vtiger');
exports.welcome = (req, res, next) => {
const vtigerClass = new vTiger();
console.log(vtigerClass.getchallengeTokenVtiger())
res.status(200).json({
data: vtigerClass.getchallengeTokenVtiger()
});
}
from this file as an response I get:
{
"data": {}
}
while from the console.log(vtigerClass.getchallengeTokenVtiger()) line I get this:
Promise { undefined }
Where am I doing wrong?
Thanks

you probably don't want to use the .then in an async function. you should
const response = await axios.get(...)
if (response.data.success) {
token = response.data.result.token;
tokenmd5 = md5(token + this.password);
return tokenmd5;
}
else return null;
Or you can create a variable in your function called tokenmd5 i.e.
let tokenmd5 = ''
set its value in the .then, then return tokenmd5 at then end of your function NOT in the .then
THEN:
for your console.log you want:
exports.welcome = async (req, res, next) => {
const vtigerClass = new vTiger();
console.log(await vtigerClass.getchallengeTokenVtiger())
res.status(200).json({
data: vtigerClass.getchallengeTokenVtiger()
});
}

Related

NodeJS API Proxy Server - Post Requests Error 404 - Routing

I am new at NodeJS and am trying to implement a proxy server for my GET requests. GET requests works fine can also update my UI as it should be by performAction and chained promises, however something is wrong with my POST request, I always get a 404 despite I defined the route, it pops up after UI update. Can anybody help me? Thanks!
SERVER
const express = require('express')
const cors = require('cors')
const rateLimit = require('express-rate-limit')
require('dotenv').config()
const errorHandler = require('./middleware/error')
const bodyParser = require('body-parser')
// support parsing of application/json type post data
//support parsing of application/x-www-form-urlencoded post data
const PORT = process.env.PORT || 5000
const app = express()
app.use(bodyParser.urlencoded({ extended: true }));
// Rate limiting
const limiter = rateLimit({
windowMs: 10 * 60 * 1000, // 10 Mins
max: 100,
})
app.use(limiter)
app.set('trust proxy', 1)
// Enable cors
app.use(cors())
// Set static folder
app.use(express.static('public'))
// Routes
app.use('/api', require('./routes'))
// Error handler middleware
app.use(errorHandler)
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
API PROXY SERVER
const url = require('url')
const express = require('express')
const router = express.Router()
const needle = require('needle')
const apicache = require('apicache')
// Env vars
const API_BASE_URL = process.env.API_BASE_URL
const API_KEY_NAME = process.env.API_KEY_NAME
const API_KEY_VALUE = process.env.API_KEY_VALUE
// Init cache
let cache = apicache.middleware
let projectData = {}
router.get('/', cache('2 minutes'), async (req, res, next) => {
try {
const params = new URLSearchParams({
[API_KEY_NAME]: API_KEY_VALUE,
...url.parse(req.url, true).query,
})
console.log('${API_BASE_URL}?${params}')
const apiRes = await needle('get', `${API_BASE_URL}?${params}`)
const data = apiRes.body
// Log the request to the public API
if (process.env.NODE_ENV !== 'production') {
console.log(`REQUEST: ${API_BASE_URL}?${params}`)
}
res.status(200).json(data)
} catch (error) {
next(error)
}
})
function sendForecastData(req, res) {
const { date, temp, content } = req.body;
let journal_entry_new = new Object();
journal_entry_new.date = date;
journal_entry_new.temp = temp + "°C";
journal_entry_new.content = content;
idx_entry = String("entry_" + idx)
idx = idx + 1
projectData[idx_entry] = JSON.stringify(journal_entry_new);
console.log(projectData)
res.send(projectData)
console.log("Post sucessful.")
}
router.post('/', cache('2 minutes'), async (req, res, next) => {
const postObject = needle.post('/addData', req.body, sendForecastData)
return postObject;
})
function readData(req, res) {
res.send(projectData)
console.log(projectData)
console.log("Read sucessful.")
}
router.get('/readData', readData)
module.exports = router
This is my app.js
//Event-Listener
document.getElementById('generate').addEventListener('click', performAction);
//Declare Fetch Function
//User Input
const the_date = document.getElementById('date');
const temp = document.getElementById('temp');
const content = document.getElementById('content');
// Create a new date instance dynamically with JS
let d = new Date();
let newDate = (d.getMonth() + 1) + "." + (d.getDate()) + '.' + (d.getFullYear());
//Proxy
const fetchWeather = async (zipcode) => {
const url = `/api?q=${zipcode}`
const res = await fetch(url)
const data = await res.json()
console.log(data)
return data;
}
const postData = async (url, data) => {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
try {
const data = await response.json();
return data
}
catch (error) {
console.log("error", error);
}
}
const readData = async () => {
const request = await fetch('/readData');
try {
// Transform into JSON
const readData = await request.json()
return readData
} catch (error) {
console.log("error", error);
}
}
const UpdateUI = async (data) => {
console.log("Data received:")
console.log(data)
console.log("Date: " + data[Object.keys(data)[0]])
console.log("Temp: " + data[Object.keys(data)[1]])
console.log("Content: " + data[Object.keys(data)[2]])
document.getElementById('temp').innerText = "Temperature is: " + data[Object.keys(data)[1]]
document.getElementById('date').innerText = "Date is: " + data[Object.keys(data)[0]]
document.getElementById('content').innerText = "Feeling is: " + data[Object.keys(data)[2]]
console.log("Updated UI")
}
function performAction(e) {
//Check if user input is available
if (document.getElementById('zip').value == "") {
alert("Please type in a zipcode, then I will know where to look up the weather for
you!");
return
}
//Feeling now
let zipcode = (document.getElementById('zip').value).toString()
let feeling_now = (document.getElementById('feelings').value).toString()
fetchWeather(zipcode)
.then(data => {
/*let temp_k = parseFloat(data.list[0].main.temp)*/
/*let temp_c = String((temp_k - 273.15).toFixed(2)) + " °C"*/
let temp_c = parseFloat(data.main.temp) + " °C"
let feeling_now = (document.getElementById('feelings').value).toString()
console.log(temp_c)
console.log(newDate)
console.log(feeling_now)
console.log({ date: newDate, temp: temp_c, content: feelings.value })
return { date: newDate, temp: temp_c, content: feelings.value }
}).then(data => {
postData('/addData', data);
return data
})
.then(data => {
readData('/readData');
return data
})
.then(data => UpdateUI(data))
console.log(feeling_now)
return;
}
My UI is updated, however I get the following error and cannot access localhost:5000/addData - can you help why this is the case?
Defined the routes in the backend, however cannot call them from frontend

Nojde does not await for async function and array.length condition

Trying to implement Twitter API to post tweets with multiple images. I am posting requests from the admin dashboard with an AD id(not the Twitter ad) , fetching the images URL from our database and using the URLs to write image files in the upload directory. Then using the Twitter-api-2 package to post a request to Twitter API to get the mediaIdS and post the tweet.
Problem: When I write files to local upload folders, the async function also get executed, therefore cannot find the media files in the local folder, leading to an error.
const router = require('express').Router()
const { parse } = require('dotenv');
const { link } = require('joi');
const { TwitterApi } = require('twitter-api-v2')
const { FetchSingleAdBasics } = require('../helpers/fetch-single-ad-basics');
const request = require('request');
const fs = require('fs');
const path = require('path');
const https = require('https')
function saveImagesToUploads(url, path){
const fullUrl = url
const localPath = fs.createWriteStream(path)
const request = https.get(fullUrl, function(response){
console.log(response)
response.pipe(localPath)
})
}
var jsonPath1 = path.join(__dirname,'../..','uploads/0.png');
var jsonPath2 = path.join(__dirname,'../..','uploads/1.png');
var jsonPath3= path.join(__dirname,'../..','uploads/2.png');
var jsonPath4 = path.join(__dirname,'../..','uploads/3.png');
router.post('/twitter-post', async(req, res) => {
const {adId} = req.body
const imagesArr = []
const imageIdsArr = []
const {text} = req.body
const AD = adId && await FetchSingleAdBasics(adId);
const PostMessage = `${AD?.year} ${AD?.make} ${AD?.model} ${AD?.trim}\r\n${AD?.engineSize}L Engine\r\nPrice: AED${AD?.addetails[0].price}\r\nMileage: ${AD?.mileage} - ${AD?.mileageUnit}\r\nMechanical Condition: ${AD?.addetails[0].mechanicalCondition}\r\nAvailable in: ${AD?.adcontacts[0]?.location}\r\nCheckout full details at: https://ottobay.com/cars/uc/${AD?.id}`
if (!AD)
return res
.status(422)
.json({ message: "failed", error: "Ad Not Found" })
try {
imagesArr.push(await AD?.adimages[0]?.LeftSideView)
imagesArr.push(await AD?.adimages[0]?.LeftFront)
imagesArr.push(await AD?.adimages[0]?.Front)
imagesArr.push(await AD?.adimages[0]?.FrontRight)
// the following function must await for this to finish
imagesArr?.map((item,index) => {
saveImagesToUploads(item, "./uploads/" + `${index}`+ '.png')
})
const filesArr = [jsonPath1,jsonPath3,jsonPath4,jsonPath2]
console.log(filesArr)
console.log(filesArr?.length)
const idsArray = []
// this function get executed without waiting for previous function, leading to error
// this function does not apply filesArr?.length === 4 condition
filesArr?.length === 4 && await Promise.all(filesArr?.length === 4 && filesArr?.map(async (item) => {
try {
const mediaId = await client.v1.uploadMedia(item,{ mimeType : 'png' })
idsArray.push(mediaId)
return imageIdsArr;
} catch(err) {
console.log(err)
throw err;
}
}));
const response = idsArray?.length === 4 && await client.v1.tweetThread([{ status: PostMessage, media_ids: idsArray }]);
// remove files after successfull tweet
await fs.promises.readdir(jsonUploadPath).then((f) => Promise.all(f.map(e => fs.promises.unlink(`${jsonUploadPath}${e}`))))
res.json({status: 'success', response})
} catch (error) {
res.json({status: 'failed',error})
// console.log("tweets error", error.data.errors);
}
})
module.exports = router

Executing async functions in series

I'm trying to put this code into two async functions. I've managed to put the auth check into one already,but im struggling to put the api call in an async function since it has to write json files.How can I tell the auth function to run after I finish writing the json files?
var authVal = 2;
var condition1 = 3;
var condition2 = 5;
var condition3 = 8;
const fs = require('fs');
const https = require('https');
const util = require('util');
const read = util.promisify(fs.readFile);
let cmdrName = args.join(' ');
let currTime = new Date().toISOString().slice(0, 19);
cmdrName = cmdrName.toLowerCase();
console.log("\x1b[33m" + message.author.username + "\x1b[37m" + " has used " + "\x1b[33m" + ".auth " + cmdrName);
//api call
const data = new TextEncoder().encode(
JSON.stringify({ "header": { "appName": "CIABot", "appVersion": "1.0", "isDeveloped": true, "APIkey": "" }, "events": [{ "eventName": "getCommanderProfile", "eventTimestamp": currTime, "eventData": { "searchName": cmdrName } }] })
)
const options = {
hostname: 'inara.cz',
port: 443,
path: '/inapi/v1/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', d => {
fs.writeFile('./comms/inaraOutput.json', d, function (err) {
if (err) throw err;
console.log("\x1b[32m" + "successfully created " + "\x1b[33m" + "inaraOutput.json");
console.log("\x1b[37m" + "------");
});
});
})
req.on('error', error => {
console.error(error);
})
req.write(data);
req.end();
//api call ends here
//auth check
var auth = async () => {
const [json1, json2] =
await Promise
.all([
read("./comms/code.json"),
read("./comms/inaraOutput.json")
])
let jsonCode = JSON.parse(json1);
let inaraOutput = JSON.parse(json2);
//fancy auth logic here
};
auth();
You could wrap all your asynchronous calls in another asyn function and await for the executions to finish before executing the OAuth.
async function myFunction(){
await req.on('error', error => {
console.error(error);
})
await req.write(data);
await req.end();
auth();
}
myFunction()

How to return REST API response after utility execution is finished in expressJs

I have written one POST endpoint in expressJS with node.when I a make call to API It runs a utility with setInterval() and I want to send the API response after utility executes clearInterval().
How I can I wait and send response after utility execution is finished?
Please see the code below
REST API code:
const router= express.Router();
const multer= require('multer');
const {readCSVFile}= require('../util/index');
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads');
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now()+'.xlsx');
}
});
var upload = multer({storage: storage});
router.post('/fileUpload', upload.single('filename'), async (req, res) => {
readCSVFile();
res.status(201).json({id:1});
});
router.get('/',(req,res)=>{
res.sendFile(__dirname+'/index.html');
});
module.exports=router;
Utilty Code
const config = require('config')
const excelToJson = require('convert-excel-to-json')
const HttpsProxyAgent = require('https-proxy-agent')
const AWS = require('aws-sdk')
const json2xls = require('json2xls')
const fs = require('fs')
const awsConfig = {
httpOptions: {
agent: new HttpsProxyAgent(
config.get('aws.proxy')
),
}
}
AWS.config.credentials = new AWS.SharedIniFileCredentials({
profile: config.get('aws.profile'),
})
AWS.config.update(awsConfig)
let uuidv4 = require('uuid/v4')
let csv = [];
const lexRunTime = new AWS.LexRuntime({
region: config.get('aws.region'),
})
let refreshId
const readCSVFile = () => {
const csvSheet = excelToJson({
sourceFile: './Test.xlsx',
})
csvSheet.Sheet1.forEach(element => {
csv.push((element.A.slice(0, element.A.length)))
})
runTask()
refreshId = setInterval(runTask, 1000)
}
let botParams = {
botAlias: config.get('bot.alias'),
botName: config.get('bot.name'),
sessionAttributes: {},
}
const missedUtterancesArray = []
const matchedUtterancesArray = []
let start = 0
let end = 50
let count = 50
const runTask = () => {
let itemsProcessed = 0
console.log('executing...')
const arrayChunks = csv.slice(start, end)
arrayChunks.forEach((element) => {
botParams.inputText = element
botParams.userId = `${uuidv4()}`
lexRunTime.postText(botParams, function (err, data) {
itemsProcessed++
if (err) console.log(err, err.stack)
else {
if (data.intentName === null) {
missedUtterancesArray.push({
Utterance: element,
})
}
else{
matchedUtterancesArray.push({
Utterance: element,
})
}
}
if (itemsProcessed === arrayChunks.length) {
start = csv.indexOf(csv[end])
end = start + count
}
if (start === -1) {
let xls = json2xls(missedUtterancesArray)
fs.writeFileSync('./MissedUtterances.xlsx', xls, 'binary')
let matchedXls = json2xls(matchedUtterancesArray)
fs.writeFileSync('./MatchedUtterances.xlsx', matchedXls, 'binary')
console.log('File saved successfully!! ')
console.log('Total Matched utterances count: ',csv.length-missedUtterancesArray.length)
console.log('Total Missed utterances count: ',missedUtterancesArray.length)
console.log('Total Utterances count: ',csv.length)
clearInterval(refreshId)
}
})
})
}
I would have needed few more information to answer this but pardon my try if this does not work -
the setInterval method in the readCSVFile the reason. Being an asynchronous function, this will not stop the code progression.
lexRunTime.postText also looks like asynchronous. I think you'd be better off with using promises while responding to the client.

How can I access the response headers of a request that is piped to a feedparser

I am trying to parse an RSS feed using request js and feedparser-promised libraries. I am able to parse the feed using the below code.
import Bottleneck from 'bottleneck';
const feedparser = require('feedparser-promised');
const limiter = new Bottleneck({
maxConcurrent: 1,
minTime: 333,
});
const httpOptions = {
uri: val.sourcefeedurl,
resolveWithFullResponse: true,
method: 'GET',
pool: false,
headers: {
'If-None-Match': val.etag,
'If-Modified-Since': val.LastModified,
Connection: 'keep-alive',
ciphers: 'DES-CBC3-SHA',
},
};
const response = await limiter.schedule(() => feedparser.parse(httpOptions));
But since I use the feedparser-promised library I am not able to cache the etag and Last Modified from the response headers.
I tried modifying feedparser-promised like this
'use strict';
const request = require('request');
const feedParser = require('./feedParser');
const parse = (requestOptions, feedparserOptions) => {
const metaData = {};
return new Promise((resolve, reject) => {
request.get(requestOptions).on('error', reject).on('response', async resp => {
if (resp.statusCode === 304) {
reject('Source not modified');
} else if (resp.statusCode === 200) {
metaData.etagin = await resp.headers.etag;
metaData.LastModifiedin = await resp.headers['last-modified'];
metaData.LastModifiedLocal = await resp.headers['last-modified'];
// console.log(metaData);
}
}).pipe(feedParser(feedparserOptions).on('error', reject).on('response', resolve));
});
};
module.exports = {
parse
};
Below is the feedParser file
'use strict';
const FeedParserStream = require('feedparser');
module.exports = (feedparserOptions, metaData) => {
// console.log(metaData, 'herre');
const parsedItems = [];
const feedparser = new FeedParserStream(feedparserOptions);
// console.log(feedparser);
feedparser.on('readable', () => {
// console.log(resp);
let item;
while (item = feedparser.read()) {
parsedItems.push(item);
}
return parsedItems;
}).on('end', function next() {
this.emit('response', parsedItems);
});
return feedparser;
};
So my question is how do I return the response headers along with the parsedItems (as in the code) while resolving the promise.
Help is very much appreciated.
Pass the metaData on end like
'use strict';
const FeedParserStream = require('feedparser');
module.exports = (feedparserOptions, metaData) => {
// console.log(metaData, 'herre');
const parsedItems = [];
const feedparser = new FeedParserStream(feedparserOptions);
// console.log(feedparser);
feedparser.on('readable', () => {
// console.log(resp);
let item;
while (item = feedparser.read()) {
parsedItems.push(item);
}
return parsedItems;
}).on('end', function next() {
this.emit('response', { parsedItems, metaData });
});
return feedparser;
};
and your feed-parser promised as
'use strict';
const request = require('request');
const feedParser = require('./feedParser');
const parse = (requestOptions, feedparserOptions) => {
const metaData = {};
return new Promise((resolve, reject) => {
request.get(requestOptions).on('error', reject).on('response', async resp => {
if (resp.statusCode === 304) {
reject('Source not modified');
} else if (resp.statusCode === 200) {
metaData.etagin = await resp.headers.etag;
metaData.LastModifiedin = await resp.headers['last-modified'];
metaData.LastModifiedLocal = await resp.headers['last-modified'];
// console.log(metaData);
}
}).pipe(feedParser(feedparserOptions, metaData).on('error', reject).on('response', resolve));
});
};
module.exports = {
parse
};

Categories

Resources