How do I do a request.write(body) without the body? - node.js

I am using the code as shown below. However I want to include the body in the query string (which I can do fine) - however, I am unsure how to restructure thehttps.request so as to remove request.write(body) - simply using request.write() does not work as it requires a string.
Can someone help?
Thanks
var body = JSON.stringify( json.text );
const params = {
'q': body,
};
var requestUrl = url.parse( URL + queryStringify(params) );
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
};
var request = https.request(requestOptions, function(res) {
var data = "";
res.on('data', function (chunk) {
//do stuff
});
res.on('end', function () {
//do stuff
});
});
request.write(body);
request.end();

To do that, you can set your params in path field, with querystring like this :
Set your query string params into requestOptions
const querystring = require('querystring');
requestOptions.path = `/your/Path?${querystring.stringify({firstName: 'John', lastName: 'doe'})}`;
// Result is '/your/Path?firstName=John&lastName=doe'
Then, do your request
var request = https.request(requestOptions, function(res) {
res.on('data', function(chunk) {
// Do stuff
});
res.on('end', function() {
// Do stuff
});
});
request.on('error', function (err) {
// Throw err
});
request.end();
Hope it helps.

Related

Await function to finish calling another API

I am new to using async/await and having a couple issues.
I have the code below, which seems to not wait until the previous function is finished?
var url = require('url');
var path = require('path');
var https = require('https');
var request = require('request');
var url1 =
var url2 =
var url3 =
module.exports = async function (context, req) {
var call = await callUrl(context, url1);
context.log(call);
var call2 = await callUrl(context, url2);
context.log(call2);
var call3 = await callUrl(context, url3);
context.log(call3);
};
function callUrl (context, web) {
var requestUrl = url.parse(web);
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
var request = https.request(requestOptions, function(res) {
var data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
var jsonData = JSON.parse(data);
return jsonData;
});
}).on('error', function(error) {
context.log("request error:", error);
return context.done();
});
request.end();
}
I am trying to get call to happen, then when it is finished call2, then when that is finished call3.
Can someone pinpoint why this does not occur? Currently, it hits all 3 pretty much asap, and each context.log is undefined presumably because the endpoints don't return anything. Each url is another azure function app API I have created.
There is nothing I am requiring to return from each call to use, I simply want them to finish before moving on the the next function.
Your callUrl method, which you call with await, needs to be either async itself or return a Promise. Why? because the work it does is itself asynchronous.
Here's your function adapted to use a Promise and return its actual value via the resolve() callback.
function callUrl (context, web) {
var requestUrl = url.parse(web);
const requestOptions = {
hostname: requestUrl.hostname,
path: requestUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
return new Promise(function (resolve,reject) {
var request = https.request( requestOptions, function( res ) {
var data = "";
res.on( 'data', function( chunk ) {
data += chunk;
} );
res.on( 'end', function() {
var jsonData = JSON.parse( data );
resolve( jsonData );
} );
} )
.on( 'error', function( error ) {
reject(error);
} );
request.end();
});
}
Notice that you use a POST operation with no body. That's a little unconventional.

express integrating middleware into a callback response

I have middleware (API calls, not part of a route) which I want to use in a callback response.
// MIDDLEWARE EXAMPLE
var postInvoice = function(req, res){
function request(callback) {
var path='/xxx?';
var data = querystring.stringify( {
'action' : 'xxx',
'appkey' : 'xxx'',
'fromapi' : 'xxx',
'fromapiuser' : 'xxx',
'username' : 'xxx',
'shipmethod' : 'TEST',
'shipping' : '0',
'taxes' : '0'
});
var options = {
port: 443,
host: xxx,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
var postRequest = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Invoice Response: ' + chunk);
});
});
postRequest.write(data);
}
request(function(responseData) {
console.log(responseData);
});
}
I need to access the response in another route (which itself includes callback via API)
app.get('/result', function(req, res){
var resourcePath = req.param('resourcePath');
function request(callback) {
var path = resourcePath
var options = {
port: 443,
host: xxx,
path: path,
method: 'GET'
};
var postRequest = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
jsonRes = JSON.parse(chunk);
return callback(jsonRes);
});
});
postRequest.end();
}
request(function(responseData) {
console.log(responseData);
// this is where I invoke the middleware,
if(some response condition is met) {
postinvoice();
}
res.render('result', {
check: check,
response: checkout_msg
});
});
});
I'm able to view the 'Invoice Response' in console, but I cannot manipulate it in the /result route. I'd like to be able to invoke the middleware, create locals and make the locals available in /result route.
thank you,
try this
var postRequest = http.request(options, function (response) {
var body = '';
response.setEncoding('utf8');
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function () {
body = JSON.parse(body); //if response is json
return callback(body);
});
});

NodeJs Error: Can't set headers after they are sent

I am new to nodejs and stuck up with this Error:Can't set headers after they are sent. Below is my code. Please help. I used postman to test this code. It is working for the first 2 hits but on the 3rd hit this error is coming.
const http = require('http');
const fs = require('fs')
module.exports.verifyPyeval5 = function(request, response){
let filePath = "D:/PyEval/NewPyEvalRequests/solution.txt";
fs.readFile(filePath, 'utf8', function (err,data) {
var json = JSON.parse(data);
post_call(json,function(res){
response.status(200)
.json(res);
});
});
};
var post_call = function(new_val,callback){
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
callback(chunk);
});
});
post_req.write(JSON.stringify(new_val));
post_req.end();
};
var post_options = {
host: 'acclabserv',
port: '8080',
path: '/generate',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
I got it the issue is with callback function it gets called more then once.
var post_call = function(new_val,callback){
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
var str = null;
res.on('data', function (chunk) {
str += chunk;
});
res.on('end', function () {
callback(str);
});
});
post_req.write(JSON.stringify(new_val));
post_req.end();
};
One more thing to note here I dont know the type of chuck if its an object and you want array of object in response then you can use this
var str = []; //in req.on('data') str.push(chunck)

https Request in Alexa Skill

I can't seem to get HTTP requests to work in my alexa skill, here is the relevant sample code:
var https = require('https');
...
function getTreeFact(callbackFunction){
var url = 'https://alexa.phl.chs.network/treefacts/index.php';
https.get(url, function(res){
var body = '';
res.on('data', function(chunk){
body += chunk;
});
res.on('end', function(){
var gameResponse = JSON.parse(body);
callbackFunction(gameResponse);
});
}).on('error', function(e){
// Handle error
});
}
...
this.getTreeFact(function (responseMessage){
this.emit(':tell', responseMessage.message);
});
I have no idea what I am doing wrong, I think I am making the HTTP request correctly. I know the skill works without this (simply commenting out the last three lines and replacing with just this.emit(':tell', 'hello') works fine).
Let me explain my below code...Here I have used https request in the "LaunchRequest"
which in turns gives me a response and with that response and I'm making my alexa to speak
note: jsonplaceholder.typicode.com is very useful for testing your https req and response
Simply use this code in your aws online editor console make sure you type the right intent name and invocation name.
exports.handler = (event, context, callback) => {
var speechResult;
switch (event.request.type) {
case "LaunchRequest":
var resultis;
const querystring = require('querystring');
const https = require('https');
var postData = querystring.stringify({
'msg' : 'Hello World!'
});
var options = {
hostname: 'jsonplaceholder.typicode.com',
path: '/posts',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = https.request(options, (res) => {
//console.log('statusCode:', res.statusCode);
//console.log('headers:', res.headers);
res.on('data', (d) => {
//console.log("my data is "+d);
var obj = JSON.parse(d);
var resul = obj.msg;
resultis = JSON.stringify(resul);
context.succeed(generateResponse(buildSpeechletResponse(resultis, true)));
});
});
req.on('error', (e) => {
console.error(e);
});
req.write(postData);
req.end();
break;
case "IntentRequest":
switch (event.request.intent.name) {
case "MyIntent":
var a = "are you ready";
context.succeed(generateResponse(buildSpeechletResponse(a, true)))
break;
}
break;
}
}
//Alexa Speech function
buildSpeechletResponse = (outputText, shouldEndSession) => {
return {
outputSpeech: {
type: "PlainText",
text: outputText
},
shouldEndSession: shouldEndSession
}
}
generateResponse = (speechletResponse) => {
return {
version: "1.0",
response: speechletResponse
}
}
Alexa's official github page has a very thorough documentation on api calls. Check their Cooking list skill documentation it covers all of the get and post requests https://github.com/alexa/alexa-cookbook
and https://github.com/alexa/ main repo for other samples.
You better use a promise version, for example
https://github.com/request/request-promise
To me it looks like
this.emit(':tell', responseMessage.message);
should be
this.emit(':tell', responseMessage);
I can't see any .message in this
var gameResponse = JSON.parse(body);
callbackFunction(gameResponse);

AWS Lambda - NodeJS POST request and asynch write/read file

I am new to NodeJS and inside of AWS Lambda I am trying to make a POST request that calls an external API with a JSON object, creates a document with the response and then reads the contents of the file.
Coming from a Ruby background, I'm thinking the problem stems from my unfamiliarity with asynchronous programming, but I've tried using callbacks and readfileSync just to debug with no luck.
Any help would be appreciated.
var querystring = require('querystring');
var https = require('https');
var fs = require('fs');
exports.handler = function(event, context) {
console.log('Received event:', JSON.stringify(event, null, 2));
var operation = event.operation;
delete event.operation;
var accessKey = event.accessKey;
delete event.accessKey;
var templateName = event.templateName;
delete event.templateName;
var outputName = event.outputName;
delete event.outputName;
var req = {
"accessKey": accessKey,
"templateName": templateName,
"outputName": outputName,
"data": event.data
};
function doPost(data, callback) {
// Build the post string from an object
var post_data = JSON.stringify(data);
// An object of options to indicate where to post to
var post_options = {
host: 'hostname.com',
port: '443',
path: '/path/to/api',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
// Set up the request
var file = fs.createWriteStream(outputName);
var post_req = https.request(post_options, function(res) {
res.setEncoding('utf8');
res.pipe(file);
res.on('response', function(response) {
console.log(response);
});
res.on('error', function(e) {
context.fail('error:' + e.message);
})
res.on('end', function() {
context.succeed('success, end request listener');
});
});
// post the data
post_req.write(post_data);
post_req.end();
callback();
}
function printFileContents() {
fs.readFileSync(outputName, 'utf8', function (err, data) {
console.log('file contents:' + data);
});
}
switch (operation) {
case 'create':
// Make sure there's data before we post it
if(req) {
doPost(req, printFileContents);
printFileContents();
}
break;
...
}
};
In general, I'd recommend starting like this:
var querystring = require('querystring');
var https = require('https');
var fs = require('fs');
exports.handler = function(event, context) {
console.info('Received event', event);
var data = {
"accessKey": accessKey,
"templateName": templateName,
"outputName": outputName,
"data": event.data
};
// Build the post string from an object
var post_data = JSON.stringify(data);
// An object of options to indicate where to post to
var post_options = {
host: 'hostname.com',
port: '443',
path: '/path/to/api',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
var post_request = https.request(post_options, function(res) {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
context.done(body);
});
res.on('error', function(e) {
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
};
You can see I simplified your code quite a bit. I'd recommend avoiding the file system since that would slow down your program. I'm also not sure about what is the real goal of your function so I just return the HTTP response.

Resources