Why is my (try-catch) code executed too soon in NodeJS? - javascript

On the response of an HTTP GET call (with native http module), I try toJSON.parse() the response after the end event is emitted. I know for sure the the data i'm getting is valid JSON but still the JSON.parse throw an error. And my logs indicate that the JSON.parse is invoked before it should.
res.on("end", () => {
console.log('Req ended message is', body);
try {
var passport = JSON.parse(body);
} catch (e) {
w.info(
"Cannot parse the response from : " +
process.env.mongo_api_host +
" | error : " +
e
);
}
callback(passport);
return;
});
And my log shows :
info: Getting MongoDB passport for model : CESI
info: Cannot parse the response from : mongo_api | error : SyntaxError: Unexpected end of JSON input
info: Req ended message is *long valid JSON data*
We can clearly see in the logs that the parse error is caught and logged before the "Req ended message is : ... stuff".
What am I missing ?
Edit 1 :
Even by putting callback(passport) inside try block as suggested in comment it still does it :
res.on("end", () => {
try {
console.log("Req ended message is", body);
var passport = JSON.parse(body);
//TODO What if you get an array ?
if (passport._id) delete passport._id;
callback(passport);
} catch (e) {
w.info(
"Cannot parse the response from : " +
process.env.mongo_api_host +
" | error : " +
e
);
}
return;
});

Related

SyntaxError: Unexpected token v in JSON at position 2

I am running a node.js server running express.js on my local machine and need to decode a request made by the client, that contains a json string in it. I run the code below and get the following error.
SyntaxError: Unexpected token v in JSON at position 2
at JSON.parse (<anonymous>)
at C:\myLocation\source\repos\server\server\server.js:144:19
at Layer.handle [as handle_request] (C:\myLocation\source\repos\server\server\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\myLocation\source\repos\server\server\node_modules\express\lib\router\index.js:317:13)
My request is
http://localhost:1337/%7B%22Code%22:%22VNdVwY9iWhFZ114CjcDZbY%22,%22Chat%22:%22Test.txt%22%7D
The expected json is
{"Code":"VNdVwY9iWhFZ114CjcDZbY","Chat":"Test.txt"}
I get the json, but it still gives me the same error.
My code:
app.use(function (req, res) {
//console.log(req.url)
var myStr = req.url.replace('/', '')
if (myStr != false) {
let decodeStr = decodeURIComponent(myStr)
var test = JSON.parse(decodeStr)
var json = JSON.stringify(test)
if (json.includes(createkey)) {
console.log("Create: " + json)
createFile(req, res, test)
} else if (json.includes(modKey)) {
console.log("Modify: " + json)
modifyFile(req, res, test)
} else if (json.includes(readFileKey)) {
console.log("Read: " + json)
readFile(req, res, test)
}
} else {
res.sendStatus(404)
console.log("home")
}
})
Why do I get the error?
Edit 1
I added console.log(decodeStr)but I still get the error. It returns {"Code":"VNdVwY9iWhFZ114CjcDZbY","Chat":"Test.txt"}
{"Code":"'GAHGAaphgAP:gjpaGHAHAG{AaGRAP;GHPG;RA","Chat":"Test.txt"} is not a valid json, that's why you encounter that error,
The other way around, you could parse
JSON.parse('{"Code":"\'GAHGAaphgAP:gjpaGHAHAG{AaGRAP;GHPG;RA","Chat":"Test.txt"}')
Try
var uri = "http://localhost:1337/%7B%22Code%22:%22%5C'GAHGAaphgAP:gjpaGHAHAG%7BAaGRAP;GHPG;RA%22,%22Chat%22:%22Test.txt%22%7D";

Azure Function - js - not running correctly, but no error in the logs

Am trying to build a Function to get data from my IoTHub and send the data to my web service via GET.
This is what I have in my Function:
var http = require('https');
module.exports = function (context, IoTHubMessages) {
IoTHubMessages.forEach(message => {
// context.log(`Processing message9: ${JSON.stringify(message)}`);
console.log(`what the what???`);
let url = `<my site in Azure>.azurewebsites.net`;
console.log(url);
let path = "/sensor/" + message.d1 + "/" + message.d2 + "/" + message.d3 + "/";
console.log(path);
var req = http.request({
host: url,
path: path,
method: 'GET'
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
req.on('end', function(e) {
console.log('finished with request');
});
req.end();
});
context.done();
};
The logs look like this:
2019-02-10T06:06:22.503 [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='', Id=ea6109b0-5037-4f15-9efc-845222c6f404)
2019-02-10T06:06:22.512 [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=ea6109b0-5037-4f15-9efc-845222c6f404)
2019-02-10T06:06:22.786 [Information] Executing 'Functions.IoTHub_EventHub1' (Reason='', Id=f344c44f-a6ff-49b3-badb-58429b3476dc)
2019-02-10T06:06:22.796 [Information] Executed 'Functions.IoTHub_EventHub1' (Succeeded, Id=f344c44f-a6ff-49b3-badb-58429b3476dc)
If I uncomment this line :
context.log(`Processing message9: ${JSON.stringify(message)}`);
then the JSON data is displayed in the log output. In between the Executing and Executed pairs I see:
2019-02-10T05:59:28.906 [Information] Processing message9: {"topic":"iot","d1":"200","d2":"200","d3":"200"}
I am not getting my GET request
I don't see the console.log messages after the initial stringify line
I don't see any errors.
I've tried different quotation marks to see if Node preferred one or the other.
Occasionally when restarting the Function I see a message like this in the log, but ignored it as the log had my JSON string
2019-02-10T06:00:10.600 [Error] Executed 'Functions.IoTHub_EventHub1' (Failed, Id=2b3959cd-5014-4c50-89a3-77e37f2a890e)
Binding parameters to complex objects (such as 'Object') uses Json.NET serialization.
1. Bind the parameter type as 'string' instead of 'Object' to get the raw values and avoid JSON deserialization, or
2. Change the queue payload to be valid json. The JSON parser failed:
Unexpected character encountered while parsing value: T. Path '', line 0, position 0.
The problem here is that the forEach loop is not a loop that is waiting for the result before calling context.done
When this happens as #nelak points out in his comment, the azure function stops and nothing else happens.
Observe the following. I decided to replace the http library for a simple setTimeout function, but this is more or less the same. What is happening with your code, is ilustrated in the next snippet, notice the order in which the console.log are called.
const myFn = function (context, IoTHubMessages) {
IoTHubMessages.forEach(message => {
console.log('inside foreach!')
setTimeout(() => {
console.log('inside settimeout, this is when your request is answered!')
}, 1)
});
console.log('outside all!')
};
myFn(null, [0, 1])
If you waned a different behaviour you could rewrite this with the async-await pattern and then it seems syncronous but it's actually asynchronous.
var callIt = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('inside settimeout!')
return resolve('ok')
}, 1)
})
}
var myFnAwait = async (context, IoTHubMessages) => {
for (i of IoTHubMessages){
console.log('before settimeout')
await callIt()
console.log('after timeout')
}
console.log('outside all!')
};
myFnAwait(null, [0, 1])

Retrieving data from json and a url

I have a question, what can I do to get specific data back and send to my channel when I type !test?
Normally, when I issue a request to this URL I get the following response:
http://192.168.1.12/JSON?request=getstatus&ref=4030
{"Name":"HomeSeer Devices","Version":"1.0","Devices":[{"ref":4030,"name":"ttt","location":"ttt","location2":"ttt","value":0,"status":"Off","device_type_string":"AC Input Device Unknown Sensor","last_change":"\/Date(1548247933316)\/","relationship":0,"hide_from_view":false,"associated_devices":[],"device_type":{"Device_API":4,"Device_API_Description":"Plug-In API","Device_Type":73,"Device_Type_Description":"Plug-In Type 73","Device_SubType":97,"Device_SubType_Description":"AC[16B5BB2-10]a\u0002y\u0002\u00020\u00020\u00020\u00020\u00020\u00020\u0002n\u00021\u00020"},"device_image":"","UserNote":"","UserAccess":"Any","status_image":"/images/HomeSeer/status/off.gif","voice_command":"tttt","misc":4864}]}
I want the bot to reply with that status every time I execute the !test command.
How can I do that?
Next question: how can I set it to send the request with the value parameter?
http://192.168.1.12/JSON?request=controldevicebyvalue&ref=4030&value=0
I want that if I type !Device 0 it sets value to 0 by issuing that request.
This is how I'm handling commands:
client.on('message', message => {
// If the message is "ping"
if (message.content === '!ping') {
// Send "pong" to the same channel
message.channel.send('pong');
}
});
You can use the request package from npm. You can use the command below to install it:
To use it you first need to require it, then simply put the URL you want to request to: the result will be passed to the callback:
const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
In your case, I would do it like this:
client.on('message', message => {
// Detect the command
if (message.content.startsWith('!status')) {
// Issue the request
request('http://192.168.1.12/JSON?request=getstatus&ref=4030', (error, response, body) => {
// If there has been an error, log it
if (error) console.error(error);
// Otherwise, you can reply with the JSON you got back
else message.channel.send("```json\n" + body + "\n```");
});
}
});
If you want to turn that body string into an object, you'll need to JSON.parse() it.
request('http://192.168.1.12/JSON?request=getstatus&ref=4030', (error, response, body) => {
let object = JSON.parse(body);
// Once you have the object you can get all of its properties like you'd normally do
});
Your second problem can be solved in the same way: you just need to set thonURL depending of the argument.
If you still haven't, you'll need to create an argument parser: there are a lot of ways to do that, I'll just show you the easiest one for this example:
client.on('message', message => {
let args = message.content.split(' '), // Get the arguments
command = args.shift(); // Let the first be the command
// If there's no first argument, reply with this message
if (!args[0]) return message.reply("Please enter a value.");
if (command == '!device') {
request('http://192.168.1.12/JSON?request=controldevicebyvalue&ref=4030&value=' + args[0], (error, response, body) => {
// If there has been an error, log it
if (error) console.error(error);
// Otherwise, you can reply with the JSON you got back
else message.channel.send("```json\n" + body + "\n```");
});
}
});
If you need the object from body for some reason, you can parse it as shown above.
Try installing and importing the opn module:
Command Line: $ npm install opn
Then install it into your code: const opn = require('opn')
Then something along the lines of
if (message.content == "!Device 0") {
opn('http://192.168.1.12/JSON?request=controldevicebyvalue&ref=4030&value=0');
}

Valid JSON (for real) is throwing error in JSON.Parse

I am at a dead end. I am baffled. I am passing a stringified dictionary from Python (using json.dumps()) through UDP to an Ionic 2 (Typescript) application.
The python code generating the messages:
message = { 'time' : str(round(float(op('indexFraction')[0]),3)) }
messageJSON = json.dumps(message)
#messageJSON = json.JSONEncoder().encode(message)
print(messageJSON)
op('udpout').send(messageJSON) #sending out of TouchDesigner
My callback function on the Ionic side looks like this:
socket.on('message', function (message, remoteAddress) {
if (message.length > 0) {
console.log(message, typeof(message));
// alert(message);
// process response message
var data = JSON.parse(message);
console.log(data);
if (data.time) {
alert(data.time);
}
}
});
A sample message looks like this (typeof string):
{"time": "0.934"}
// this is a string, as evidenced by the Console.log
JSON.parse() throws the following:
index.html:1 Uncaught SyntaxError: Unexpected token in JSON at position 17
I've tried all kinds of variants on the object. It passes as valid on JSONlint. It's so simple, no wacky characters. Any ideas?
Thanks,
Marc

Parse-Server : Error when executing save Parse Objects with Parse.Cloud.when

I'm migrating our app on parse.com to parse-server application on AWS.
There is a problem on my code below though this is working on parse.com
This function is save post with text and picture from iOS devices.
The last part of "savePostComment" seems to occur error.
The parse-server's version is 2.2.25.
Parse.Cloud.define("savePost", function(request, response){
...
Parse.Cloud.run(
"savePostImage",
request.params
).then(function(savePostImageResult){
...
return Parse.Cloud.run(
"savePostComment",
request.params
);
})
...
}
Parse.Cloud.define("savePostImage",function(request,response){
...
file.save().then(function(savedFileResult){
response.success(savedFileResult);
},function(error){
response.error("saveImage error : " + error);
});
});
Parse.Cloud.define("savePostComment",function(request,response){
var userData_objectId = request.params.userData_objectId;
var user = request.params.user;
var userData_pointer = request.params.userData_pointer;
var user_objectId = request.params.user_objectId;
var comment_text = request.params.comment_text;
var comment_location = request.params.comment_location;
...
postObject.set("comment_text",comment_text);
postObject.set("comment_location",comment_location);
...
if(userData_pointer){
...
} else if(!userData_pointer) {
// execute query
Parse.Promise.when(
Parse.Cloud.run(
"returnPFUser",
{"user_objectId":user_objectId}
),
Parse.Cloud.run(
"returnUserData",
{"userData_objectId":userData_objectId}
)
)
.then(function(returnPFUserResult,returnedUserData){
postObject.set("user",returnPFUserResult);
postObject.set("userData_objectId",userData_objectId);
postObject.set("userData_pointer",returnedUserData);
returnedUserData.set("lastPost",postObject);
// This part seems to occur error
return Parse.Promise.when([returnedUserData.save(),postObject.save()])
})
.then(function(savedUserData,savedPostObject){
response.success(savedPostObject);
},function(error){
response.error(error);
});
}
});
The error log is below.
error: Failed running cloud function savePostComment for user undefined with:
Input: {"comment_location_latitude":35.75201777186803,"...
Error: {"code":141,"message":{}} functionName=savePostComment, code=141, ...
error: Error generating response. ParseError {
code: 141,
message: [Error: Cannot create a pointer to an unsaved Object.] } code=141, ...
Any ideas appreciated.
Thank you for reading this to the end.

Categories