I saw the the request library was depreciated, so I have been trying to switch to Node's https method instead. I pieced together this basic request function so far.
const https = require('https')
function httpRequest(options) {
return new Promise((resolve, reject) => {
const serverRequest = https.request(options, response => {
let body = ''
response.on('data', function (d) {
body += d
});
response.on('end', function () {
resolve(JSON.parse(body))
})
})
serverRequest.on('error', err => {
reject(err)
})
serverRequest.end()
})
}
It works, but causes eslint to throw prefer-arrow-callback. I don't fully understand why https uses the .on syntax in the first place, so I'm wondering if this function can be re-written in a way that gets rid of the warning and is more in line with modern JavaScript.
I believe that that error means to say it would prefer a Lambda function definition. If you are new to lambda functions, they are formatted as such:
(parameters) => {
}
Try re-writing your code like this:
response.on('data', (d) => {
body += d;
});
response.on('end', () => {
resolve(JSON.parse(body));
});
As for the use of .on, its just how Node formats event listeners.
Related
I am trying the whole day to get some https request running.
My code so far does not work, after calling it, i am running in an "Unhandled error RangeError: Maximum call stack size exceeded at Function.entries"
import * as https from "https";
function openRequest(options : any)
{
return new Promise((resolve, reject) => {
const request = https.request(options).on('response', (response : any) => {
resolve(response);
}).on('error', (error : any) => {
reject(error);
});
request.end();
});
}
I have to use a default library, so another one won't do the work.
Can someone tell me where i am dooing something wrong?
I've got this stuff to run, typescript isn't my native language and i really don't won't to make my living out of it but some stranger in the internet used to "await for" the res object in a loop:
const request = https.request(options, async (res : any) => {
res.setEncoding("utf-8");
let result = "";
for await (const chunk of res)
{
result += chunk;
}
resolve(result);
}).on("error", (error) => {
reject(error);
});
request.end();
I really don't know, if on("error"...) will work, because .on("response"...) has failed so far. But at least, in a good day at full moon, this code runs.
My code:
var price = {};
function getPrice(price) {
const https = require('https');
var item = ('M4A1-S | Decimator (Field-Tested)')
var body = '';
var price = {};
https.get('https://steamcommunity.com/market/priceoverview/?appid=730&market_hash_name=' + item, res => {
res.on('data', data => {
body += data;
})
res.on('end', () => price ['value'] = parseFloat(JSON.parse(body).median_price.substr(1))); //doesnt add to dict
}).on('error', error => console.error(error.message));
}
price['test'] = "123" //adds to dict fine
getPrice(price)
console.log(price);
Output:
{ test: '123' }
as you can see, the "test: 123" gets added, but the "value: xxx" from the function doesn't. Why is that?
There are two main problems here:
You're redeclaring the variable inside your function so you're declaring a separate, new variable and modifying that so the higher scoped variable, never gets your .value property.
You're assigning the property inside an asynchronous callback that runs sometime later after your function has returned and thus your function actually returns and you do the console.log() too soon before you have even obtained the value. This is a classic issue with return asynchronously obtained data from a function in Javascript. You will need to communicate back that data with a callback or with a promise.
I would also suggest that you use a higher level library that supports promises for getting your http request and parsing the results. There are many that already support promises, already read the whole response, already offer JSON parsing built-in, do appropriate error detection and propagation, etc... You don't need to write all that yourself. My favorite library for this is got(), but you can see a list of many good choices here. I would strongly advise that you use promises to communicate back your asynchronous result.
My suggestion for fixing this would be this code:
const got = require('got');
async function getPrice() {
const item = 'M4A1-S | Decimator (Field-Tested)';
const url = 'https://steamcommunity.com/market/priceoverview/?appid=730&market_hash_name=' + item;
const body = await got(url).json();
if (!body.success || !body.median_price) {
throw new Error('Could not obtain price');
}
return parseFloat(body.median_price.substr(1));
}
getPrice().then(value => {
// use value here
console.log(value);
}).catch(err => {
console.log(err);
});
When I run this, it logs 5.2.
You're actually console.logging .price before you're setting .value; .value isn't set until the asynchronous call fires.
You are declaring price again inside the function and also not waiting for the asynchronous task to finish.
const https = require("https");
const getPrice = () =>
new Promise((resolve, reject) => {
const item = "M4A1-S | Decimator (Field-Tested)";
let body = "";
return https
.get(
`https://steamcommunity.com/market/priceoverview/?appid=730&market_hash_name=${item}`,
res => {
res.on("data", data => {
body += data;
});
res.on("end", () =>
resolve(
parseFloat(JSON.parse(body).median_price.substr(1))
)
);
}
)
.on("error", error => reject(error));
});
const main = async () => {
try{
const price = await getPrice();
//use the price value to do something
}catch(error){
console.error(error);
}
};
main();
I am trying to access what a function returns in node.js
I have the following function:
function getImg(callback) {
https.get('https://api.nasa.gov/planetary/apod?api_key=api-key', response => {
let data = "";
response.on('data', chunk => {
data += chunk;
});
response.on('end', () => {
let img = JSON.parse(data).hdurl;
callback(null, img);
})
}).end();
}
let image = getImg(function(err, image) {
console.log(image);
})
res.render('index', {
indexCSS: true,
image
})
It can log it to the console correctly, but if I want to access the value of the variable like I do in the last line of my code or if I console.log(image) I get undefined.
What have I done wrong. How can I access what the function produces?
It is a callback style function which wouldn't return any thing. Better to convert it to promise sttyle and use async/await to get the value in a variable
function getImg() {
return new Promise((resolve, reject) => {
https.get('https://api.nasa.gov/planetary/apod?api_key=api-key', response => {
let data = "";
response.on('data', chunk => {
data += chunk;
});
response.on('end', () => {
let img = JSON.parse(data).hdurl;
resolve(img);
})
}).end();
});
}
(async() => {
let image = await getImg();
res.render('index', {
indexCSS: true,
image
});
})();
You can't really store the return value of your function like that. Unfortunately JS is non-blocking, so the code will continue to execute past it, before it has a chance to return that value from the https request. I am not sure exactly when you call this function, but you could call res.render in the callbacks response after calling getImg() without assigning its value to something. You can use promises, otherwise it's better to handle the response you need when it is returned from the callback. That would just be a simple call like:
getImg(function(err, image) {
res.render('index', {
indexCSS: true,
image
});
})
Within whatever route is calling this function. You just cannot assign any kind of return value from a callback to a variable (really not recommended at least) in the normal way.
I have copied the very good code from https://www.tomas-dvorak.cz/posts/nodejs-request-without-dependencies/ to make a http request in nodejs using native modules.
I want to be able to use the data value later on in the script.
I know this is a common issue with newbies and async code, i just CANNOT understand this yet and have struggled for weeks to get it.
I have coped much code, watched youtube, talked to people, its flippen hard..
const getContent = function(url) {
return new Promise((resolve, reject) => {
const https = require('https')
const request = https.get(url, (response) => {
// handle http errors
if (response.statusCode < 200 || response.statusCode > 299) {
reject(new Error('Failed to load page, status code: ' + response.statusCode));
}
// temporary data holder
const body = [];
// on every content chunk, push it to the data array
response.on('data', (chunk) => body.push(chunk));
// we are done, resolve promise with those joined chunks
response.on('end', () => resolve(body.join('')));
});
// handle connection errors of the request
request.on('error', (err) => reject(err))
})
}
getContent('https://myapi/json')
.then((data) => console.log(data))
.catch((err) => console.error(err))
// I want to use the "data" value down here in my script. I want to do things with the "data" value like JSON.parse(data)
console.log(data) //undefined
let json = JSON.parse(data) //undefined
console.log('after')
my result for data is undefined
How can i use data down here below all the code above?
You can setup a callback and access your data within this callback, this pattern should be easy enough to use.
getContent('https://myapi/json')
.then(useData)
.catch((err) => console.error(err))
// Use this callback to do what you want with your data!
function useData(data) {
console.log(data);
let json = JSON.parse(data);
}
Or using async / await ( this might be more intuitive!):
async function testAwait() {
let data = await getContent('https://myapi/json');
console.log("data: ", data);
}
testAwait();
I am trying to write my first Alexa Skill and I am doing an http request which works fine, however I would like to wrap this into a function that I can call from my main code.
It is not working and I am not quite sure how I can store the response into a variable, here is my code so far:
function getValue(loc) {
var endpoint = 'URLHERE'
var something = ""
var body = ""
https.get(endpoint, (response) => {
response.on('data', (chunk) => {
body += chunk
})
response.on('end', () => {
data = JSON.parse(body)
something = data.result.node.value;
})
})
return something;
}
This is on amazon and using lambda for the functions using node.js
which I call getValue('test') using
var result = getValue('test')
it just returned undefined.
Any idea's? Thanks
I imagine because its an asynchronous call its not setting the value due to callback but I have tried implementing this and cannot get it to work.
Thanks
You're returning from your function before the callback of http.get, mixing Synchronous with Asynchronous behaviour.
So your function is returning something which hasn't been defined yet.
Try this instead :
function getValue(loc,cb) {
let endpoint = 'URLHERE'
let something = ""
let body = ""
https.get(endpoint, (response) => {
response.on('data', (chunk) => {
body += chunk
})
response.on('end', () => {
data = JSON.parse(body)
cb(data.result.node.value);
})
})
}
getValue(test,(result)=>{
//do something with result here;
});