I have a RESTish api on a node js server. When it receives a GET request, it is to call a function that will then be calling another server get function. The code looks like this:
var server = http.createServer(function(request, response) {
console.log("YEAHHH! ", request.method);
var string='';
// Inside a request handler method
if (request.method == "OPTIONS") {
console.log("options");
// Add headers to response and send
//response.writeHead(statusCode, responseHeaders);
response.writeHead(success,responseHeaders);
response.end();
}
if(request.method == "GET") {
string = soso();
}
console.log("*******", string);
response.writeHead(success,responseHeaders);
response.end(string);
});
soso() is the call to the other server. The issue is I want to send the response of the soso() function before its finished so all I'm getting is an empty string.
How do I get around this?
I'm sure this is a duplicate but can't quite find what I'm looking for. So, any help is appreciated.
EDIT
Code for the soso function:
var soso = function () {
console.log("this is being called");
var options = {...}
var req = https.get( options, function(res) {
var str = '';
res.on('data', function ( chunk ) {
str += chunk;
})
res.on('end', function () {
console.log ( "str is: ", str );
string = str;
})
req.end();
console.log(res.statusCode);
console.log(responseHeaders);
});
}
You can try something like this , I am not sure. I have not tested this. Pass the response object in soso function, then use response.end(string); after get request gets end.
var server = http.createServer(function(request, response) {
console.log("YEAHHH! ", request.method);
var string='';
// Inside a request handler method
if (request.method == "OPTIONS") {
console.log("options");
// Add headers to response and send
//response.writeHead(statusCode, responseHeaders);
response.writeHead(success,responseHeaders);
response.end();
}
if(request.method == "GET") {
string = soso(response); //send response object as argument
} else {
console.log("*******", string);
response.writeHead(success,responseHeaders);
response.end(string);
}
});
soso function
var soso = fuction(response){ // we pass the response object in soso function
console.log("this is being called");
var options = {...}
var req = https.get( options, function(res) {
var str = '';
res.on('data', function ( chunk ) {
str += chunk;
})
res.on('end', function () {
console.log ( "str is: ", str );
string = str;
})
req.end();
response.writeHead(success,responseHeaders);
response.end(string);
console.log(res.statusCode);
console.log(responseHeaders);
});
}
Related
I am new in nodejs and now days i am learnig http module.
I wrote a js program for node to check if content-type is application/json in request, then it should console at 'readable' event.
What happening is: on a single request 'readable' event called twice and print the value first time and second time it returns null.
Here is Code:
var connect = require('connect');
function jsonParse(req, res, next) {
if (req.headers['content-type'] == 'application/json' && req.method == 'POST') {
var readData = '';
req.on('readable', function() {
console.log('inside readable ' + req.read());
readData += req.read();
});
req.on('end', function() {
try {
req.body = JSON.parse(readData);
} catch (e) {
}
next();
})
} else {
next();
}
}
connect()
.use(jsonParse)
.use(function(req, res) {
if (req.body) {
res.end('JSON parsed !' + req.body);
} else {
res.end('no json detected !');
}
}).listen(3000);
I am calling this like:
output is :
inside readable {
"foo":"asdf"
}
inside readable null
Please guide me how can i handle this. Thanks in advance.
You should only read from the request when data is available, so when req.read() does not return null. You can check this with a while loop.
Replace:
var readData = '';
req.on('readable', function() {
console.log('inside readable ' + req.read());
readData += req.read();
});
With:
var readData = '';
req.on('readable', function(){
var chunk;
while (null !== (chunk = req.read())){
readData += chunk;
}
});
I'm fumbling my way through node.js with massive help from people on here and I'm struggling getting the body of a GET request into a variable.
Here's the code so far:
var speechOutput;
var myCallback = function(data) {
console.log('got data: '+data);
speechOutput = data;
};
var usingItNow = function(callback) {
var http = require('http');
var url = 'http://services.groupkt.com/country/get/iso2code/IN';
var req = http.get(url, (res) => {
var body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
var result = JSON.parse(body);
callback(result);
});
}).on('error', function(e){
console.log("Got an error: ", e);
});
};
usingItNow(myCallback);
I'm using examples from other posts to try and get the body of the GET request into the speechOutput variable but it is coming out as undefined.
Ultimately I want the RestResponse.result.name in speechOutput, but I thought I would take this one step at a time. Can anyone offer any pointers?
Further to this, I have tried the following, which still came back undefined - maybe there is a bigger issue with the code? It doesn't even seem to be getting to the parse.
res.on("end", () => {
// var result = JSON.parse(body);
callback('result');
});
putting the line callback('result'); before the line var req = http.get(url, (res) => { returns 'result' but anything else is either undefined or causes an error.
Quoting Roy T. Fielding:
Server semantics for GET, however, are restricted such that a body,
if any, has no semantic meaning to the request. The requirements
on parsing are separate from the requirements on method semantics.
Don't use get request to send body parameters. Use post requests. If you want to send data within a get request, add them to the query string.
Read this for more info about bodies in get requests:
HTTP GET with request body
Update:
Try to log errors in the response, add this before you set up the listeners:
var body = "";
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// consume response data to free up memory
res.resume();
return;
}
res.on("data", (chunk) => {
body += chunk;
});
totally new to Node.js and this callback thing is driving me nuts.
I am writing a Skill for an Amazon Echo. As part of this I am trying to send an SMS using BulkSMS.com via a HTTP Request. The http.request has a callback which parses the response. (To take the BulkSMS API out of the equation in the example below I am just trying to get it working using a http request to Random.org (i.e. www.random.org/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new)
However I am getting an error saying that the callback is not defined.
{
"errorMessage": "callback is not defined",
"errorType": "ReferenceError",
"stackTrace": [
"Emergency.eventHandlers.onLaunch (/var/task/index.js:54:11)",
"AlexaSkill.requestHandlers.LaunchRequest (/var/task/AlexaSkill.js:16:37)",
"AlexaSkill.execute (/var/task/AlexaSkill.js:97:24)",
"exports.handler (/var/task/index.js:100:15)"
]
}
I am sure I am doing something totally stupid and for that I apologize, but I just can't see it.
Here is the onLaunch event handler in my index.js. Any help greatly appreciated.
Emergency.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) {
console.log("Emergency onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId);
console.log("Attempting to send SMS");
callback = function(response) {
var str = '';
console.log("In callback");
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
console.log("Getting Data");
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
console.log("End of response");
console.log(str);
});
}
http.request(options, callback).end();
console.log("Finished sending SMS");
var speechOutput = "<speak>SMS sent</speak>";
response.tell(speechOutput);
};
Full index.js is below.
'use strict';
/**
* App ID for the skill
*/
var APP_ID = "amzn1.ask.skill.eb8cf94a-848f-45ae-9792-xxxxxxxxxx";
/**
* The AlexaSkill prototype and helper functions
*/
var AlexaSkill = require('AlexaSkill');
var http = require('http');
var request = require("request");
//var Alexa = require('alexa-sdk');
var SKILL_NAME = 'Emergency';
var Emergency = function () {
AlexaSkill.call(this, APP_ID);
console.log("APP_ID set");
};
var alexaResponse = "";
//The url we want is: 'www.random.org/integers/? num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new'
var options = {
host: 'www.random.org',
path: '/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new'
};
// Extend AlexaSkill
Emergency.prototype = Object.create(AlexaSkill.prototype);
Emergency.prototype.constructor = Emergency;
Emergency.prototype.eventHandlers.onSessionStarted = function (sessionStartedRequest, session) {
console.log("Emergency onSessionStarted requestId: " + sessionStartedRequest.requestId
+ ", sessionId: " + session.sessionId);
// any initialization logic goes here
};
Emergency.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) {
console.log("Emergency onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId);
console.log("Attempting to send SMS");
callback = function(response) {
var str = '';
console.log("In callback");
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
console.log("Getting Data");
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
console.log("End of response");
console.log(str);
});
}
http.request(options, callback).end();
console.log("Finished sending SMS");
var speechOutput = "<speak>SMS sent</speak>";
response.tell(speechOutput);
};
Emergency.prototype.eventHandlers.onSessionEnded = function (sessionEndedRequest, session) {
console.log("Emergency onSessionEnded requestId: " + sessionEndedRequest.requestId
+ ", sessionId: " + session.sessionId);
// any cleanup logic goes here
};
Emergency.prototype.intentHandlers = {
// register custom intent handlers
EmergencyIntent: function (intent, session, response) {
// Get a random "never" phrase from the list
}
};
// Create the handler that responds to the Alexa Request.
exports.handler = function (event, context) {
// Create an instance of the Emergency skill.
var emergency = new Emergency();
emergency.execute(event, context);
};
However I am getting an error saying that the callback is not defined.
That's because of 'use strict'; mode.
First, strict mode makes it impossible to accidentally create global variables. In normal JavaScript mistyping a variable in an assignment creates a new property on the global object and continues to "work" (although future failure is possible: likely, in modern JavaScript). Assignments which would accidentally create global variables instead throw in strict mode:
More on this in MDN
accidentalGlobalVariable = 'hello world';
console.log(accidentalGlobalVariable); // logs hello world
In strict mode,
'use strict';
accidentalGlobalVariable = 'hello world';
console.log(accidentalGlobalVariable); // errors out
Error
accidentalGlobalVariable = 'hello world';
^
ReferenceError: accidentalGlobalVariable is not defined
In your code sample, If I run without strict mode it works,
var http = require('http');
var options = {
host: 'www.random.org',
path: '/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new'
};
callback = function (response) {
console.log('response statusCode', response.statusCode);
};
http.request(options, callback).end();
but if I run with strict mode,
'use strict';
var http = require('http');
var options = {
host: 'www.random.org',
path: '/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new'
};
callback = function (response) {
console.log('response statusCode', response.statusCode);
};
http.request(options, callback).end();
I too get error because strict mode errors out callback
callback = function (response) {
^
ReferenceError: callback is not defined
you can remedy it by
Using var or let in assignment.
var callback = function (response) {
console.log('response statusCode', response.statusCode);
};
Eliminating the need of callback all together and use an anonymous function instead.
http.request(options, function (response) {
console.log('response statusCode', response.statusCode);
}).end();
I am trying to perform a GET request to an API and return the data from the API response to the client. I think the client receives a response before the GET request to the API finishes. How can I change the code to ensure that the response from the API is passed on to the client?
if (request.method == 'POST' && request.url == '/locationdata') {
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var formattedLocation = body.replace(/[\[\]']+/g, '');
var urlAPI = 'https://api.darksky.net/forecast/166731d8eab28d33a26c5a51023eff4c/' + formattedLocation;
response.writeHead(200, { 'Content-Type': 'application/json' });
var apiData = '';
var apirequest = function () {
https.get(urlAPI, function (response) {
response.on('data', function (data) {
apiData += data;
});
response.on('end', function () {
console.log(apiData);
return apiData;
});
});
}
response.end(apirequest);
});
return;
}
You are ending the response to the client before you get all the data from the api. Moving the response.end() call up to the end of the api response should fix it:
if (request.method == 'POST' && request.url == '/locationdata') {
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var formattedLocation = body.replace(/[\[\]']+/g, '');
var urlAPI = 'https://api.darksky.net/forecast/166731d8eab28d33a26c5a51023eff4c/' + formattedLocation;
response.writeHead(200, { 'Content-Type': 'application/json' });
var apiData = '';
https.get(urlAPI, function (apiResponse) {
apiResponse.on('data', function (data) {
apiData += data;
});
apiResponse.on('end', function () {
console.log(apiData);
// send response to browser after we get all the data from the api
response.end(apiData);
});
});
// remove this because we moved it up
//response.end(apirequest);
});
return;
}
I'm getting a JSON response from a service that I want to pass on to another function. When I put a breakpoint on the var parsedData... line and one on the return resp, the parsedData line gets hit first. How can I "wait" for the request to finish before moving on in the code?
var data = sendRequest(options);
var parsedData = parseData(commits);
var sendRequest = function (options) {
var resp = {}
var request = https.request(options, function (response) {
var body = '';
response.on("data", function (chunk) {
body += chunk.toString('utf8');
});
response.on("error", function(e){
console.log(e);
})
response.on("end", function () {
resp = JSON.parse(body);
return resp;
});
});
request.end();
}
add a callback argument to sendRequest
var data = sendRequest(options, function(){
var parsedData = parseData(commits);
});
var sendRequest = function (options, callback) {
var resp = {}
var request = https.request(options, function (response) {
var body = '';
response.on("data", function (chunk) {
body += chunk.toString('utf8');
});
response.on("error", function(e){
console.log(e);
})
response.on("end", function () {
resp = JSON.parse(body);
callback(resp);
});
});
request.end();
}