I am getting following error while running code in AWS-Lambda.
TypeError: first argument must be a string or Buffer at ClientRequest.OutgoingMessage.write (_http_outgoing.js:447:11) at EventEmitter. (/var/task/index.js:52:13) at emitOne (events.js:77:13) at EventEmitter.emit (events.js:169:7) at exports.handler.eventEmitter.on.offset (/var/task/index.js:57:18)
'use strict';
let https = require('https');
exports.handler = (event, context, callback) => {
var ratesData =[];
var totalRecords =0;
var events = require('events');
var options = {
hostname: 'encrypted.google.com',
port: 443,
path: '/',
method: 'GET'
};
// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();
eventEmitter.on('getJson', function(offset)
{
const req = https.request(options.toString(), (res) => {
let body = '';
console.log('Status:', res.statusCode);
console.log('Headers:', JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', (chunk) => body += chunk);
res.on('end', () => {
console.log('Successfully processed HTTPS response');
// If we know it's JSON, parse it
if (res.headers['content-type'] === 'application/json')
{
var requestedJson = JSON.parse(body);
body = requestedJson.records;
totalRecords = requestedJson.total_records;
body.forEach(function(record)
{
ratesData.push(record);
});
}
callback(null, body);
});
});
req.on('error', callback);
req.write(JSON.stringify(event.data));
req.end();
});
console.log('in calling');
// Bind the connection event with the handler
eventEmitter.emit('getJson',0);
for(var i=1;i < (totalRecords/100)+1;i++)
{
eventEmitter.emit('getJson',i);
}
console.log(ratesData);
};
For one you have toString() on your options object. Remove that.
I'd also recommend testing locally as it's easier to debug.
// filename: test.js - run as node test.js
// Require your lambda
require('./index.js');
// Dummy context
var context = { };
// The event object - make sure of its format. S3 buckets pass a Records array for example
var e = { };
// Call the Lambda function
lambda.handler(e, context, function(err, result) {
console.log('------------');
console.log('Context done');
console.log(' error:', err);
console.log(' result:', result);
});
Related
i'm trying to do a HTTPS request in nodejs as follows:
var makeRequest = options => {
const req = https.request(options, res => {
// console.log('statusCode:', res.statusCode);
// console.log('headers:', res.headers);
res.on('data', d => {
process.stdout.write(d);
});
});
req.on('error', e => {
console.error(e);
});
req.end();
// return results;
};
Instead of print it i would like to return this value to another function, that should looks like:
{items:[..,..,...]}
one way would be writing the function with the callback, where the function send the request ,as the response we will getting would be stream we would have store in the temporary variable, and after successfully getting the whole response, will have to pass the response to the callback function.
const https = require('https');
const StringDecoder = require('string_decoder').StringDecoder;
const options = {
hostname: 'encrypted.google.com',
port: 443,
path: '/',
method: 'GET'
};
function getData(callbackfun){
const req = https.request(options, (res) => {
const decoder = new StringDecoder('utf-8');
let responseData = '';
res.on('data', (data) => {
responseData += decoder.write(data);
});
res.on('end',function(){
responseData += decoder.end();
callbackfun(responseData)
})
});
req.on('error', (e) => {
callbackfun(e)
});
req.end()
}
getData((result)=>{
console.log(result);
})
The following code gets the result asyncronously from the specified url, and I would like to return parsed variable out of getData method, after I receive the data, making use of async/await in nodejs version 8.* (without callback function).
function getData(v, r) {
var path = 'http://some.url.com';
var parsed = "";
http.get({
path: path
}, function(res) {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
parsed = JSON.parse(body);
// now I would like to return parsed from this function without making use of callback functions, and make use of async/await;
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
return parsed;
};
Any help is greatly appriciated.
First off let me say I recommend using the npm package request to deal with http gets, that said.
1.) Use a Promise (await does this in the background)
function getData(v, r) {
var path = 'http://some.url.com';
var parsed = '';
return new Promise((resolve, reject) => {
http.get({
path: path
}, function(res) {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
parsed = JSON.parse(body);
resolve(parsed);
});
}).on('error', function(e) {
reject(e.message);
});
});
};
Then usage would be
getData(v, r)
.then(success => console.log(success))
.catch(error => console.log(error))
2.) or callbacks You could pass in a callback as a parameter to getData (i.e. getData(v, r, callback)) then within the body of your function call it via callback(parsed) or callback(error_msg).
Then usage would be:
getData(v, r, result=>console.log(result))
or easier to read maybe:
function callback(res) {
console.log(res)
}
getData(v, r, callback)
I'm trying to execute the following code inside AWS Lambda which only makes a POST http request to an ElasticSearch.
The problem I'm facing is that it seems the nodejs request has a read timeout and the response is almost always cut and an error is thrown. I've checked that the problem is not related with AWS Lambda timeout which is set to 10 seconds and the code throws an error in less than a second.
As you can see, I've tried to put a timeout to 5secs but I think that's a connection timeout and not a read timeout.
What am I doing wrong?
var http = require('http');
exports.handler = (event, context, callback) => {
var options = {
hostname: '172.31.40.10',
port: 9200,
path: '/articles/es/_search?_source=reference',
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (body) {
var parsed = JSON.parse(body);
var b = [];
for (var i = 0; i < parsed.hits.hits.length; i++) {
b.push(parsed.hits.hits[i]._source.reference);
}
var response = {
statusCode: '200',
body: JSON.stringify(b),
headers: {
'Content-Type': 'application/json',
}
};
callback(null, response);
});
});
req.on('error', function(e) {
callback(new Error('fallo'));
});
req.setTimeout(5000, function() {req.abort;})
req.on('socket', function (socket) {
socket.setTimeout(5000);
socket.on('timeout', function() {
req.abort();
});
});
req.write(MY_QUERY_HERE);
req.end();
};
I think you should let the stream of incoming data finish before performing any data manipulation.
Example :
var http = require('http');
//var _ = require('underscore');
function MyPostRequest(callback) {
var options = {
hostname:'172.31.40.10',
port:9200,
path:'/articles/es/_search?_source=reference',
method:'POST',
headers:{'Content-Type':'application/json'}
};
http.request(options, function(res) {
var tmpstore = ''; //temp. data storage
//:Store the continuous incoming data stream
res.on('data', function(d){tmpstore += d;});
//:Data reception is done, use it now...
res.on('end', function() {
var parsed = JSON.parse(tmpstore); var b = [];
for (var i = 0; i < parsed.hits.hits.length; i++) {
b.push(parsed.hits.hits[i]._source.reference);
}
/* //I suggest using underscore module :
_.each(parsed.hits.hits,function(element, index, list){
b.push(element._source.reference);
});
*/
var response = {
statusCode:'200',
body:JSON.stringify(b),
headers:{'Content-Type':'application/json'}
};
callback(null, response);
});
//:Response contained an error
res.on('error', function(e){/*error handling*/callback(e,null);});
});
}
how to use Q to make it wait until previous response has come from the server.
What I am looking to do here is compare the response from test server and production server for the same request.
I get the responses back from both the servers, but unable to compare them since the assert statement is executed before the response comes back.
Any one know what I am doing wrong. heres the code.
var Q = require('q');
var path='';
var prodResponse = '';
var tstReponse = '';
Q.fcall(readFile())
.then(secondFunction())
.then(thirdFunction())
.then(function(){
console.log("prodResponse: "+prodResponse);
console.log("tstResponse: "+tstResponse);
assert.strictEqual(prodResponse, tstResponse)
})
.catch(function(){
console.log('error occurred');
})
.done();
function readFile(){
fs.readFile('hostname.json', function (err, data) {
if (err) return console.error(err);
path = JSON.parse(data);
return JSON.parse(data);
});
}
function secondFunction(){
var prodOptions = {
hostname: 'somehostname.com',
port: 80,
path: "/path?"+path.path,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
auth : ''
};
return http.request(prodOptions, function(res) {
console.log('Prod');
res.setEncoding('utf8');
res.on('data', function (chunk) {
prodResponse = chunk;
return chunk;
});
res.on('end', function() {
console.log('No more data in response.');
})
}).on('error', function(e) {
console.log('problem with request: ' + e.message);
}).end();
}
function thirdFunction(){
// same a second, only difference is the response http.
}
There is multiple errors in your code
Q.fcall(readFile())
Your q variable is q and not Q. So this line will crash because Q is undefined (javascript is case sensitive).
Then, readFile doesn't return any promise (in fact, it returns nothing). So the q library can't use anything to wait the end of any asynchronous work. The then callbacks will be fired immediatly.
You can use Q.ninvoke to make your readFile function return a promise, and you can use Q.defer to create and return a promise from your secondFunction:
var Q = require('q');
var path='';
var prodResponse = [];
var tstReponse = '';
readFile()
.then(secondFunction())
.then(thirdFunction())
.then(function(){
console.log("prodResponse: "+prodResponse);
console.log("tstResponse: "+tstResponse);
assert.strictEqual(prodResponse, tstResponse)
})
.catch(function(){
console.log('error occurred');
})
.done();
function readFile(){
return Q.ninvoke(fs, 'readFile', 'hostname.json').then(function (data) {
path = JSON.parse(data);
return path;
}, function (err) {
console.error(err);
});
}
function secondFunction(){
var prodOptions = {
hostname: 'somehostname.com',
port: 80,
path: "/path?"+path.path,
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
auth : ''
};
var defer = Q.defer();
var chunks = [];
http.request(prodOptions, function(res) {
console.log('Prod');
res.setEncoding('utf8');
res.on('data', function (chunk) {
chunks.push(chunk);
});
res.on('end', function() {
console.log('No more data in response.');
prodResponse = chunks.join('');
defer.resolve(prodResponse);
})
}).on('error', function(e) {
console.log('problem with request: ' + e.message);
defer.reject(e);
}).end();
return defer.promise;
}
function thirdFunction(){
// same a second, only difference is the response http.
}
I need to iterate on an array, for each item I apply an operation by calling an HTTP call.
The difficulty is that i need to syncronize this process in order to call a callback after the loop (containing the array after all the operation executed by the HTTP call).
Let's consider this short example:
function customName(name, callback) {
var option = {
host:'changename.com',
path: '/'+name,
headers: { 'Content-Type': 'application/json' },
port: 80,
method:'POST'
};
var req = http.request(option, function(res) {
var output = "";
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', function() {
var obj = JSON.parse(output);
callback(obj.res);
});
});
req.on('error', function(e) {
console.error(e.message);
});
req.end();
}
function changeNames(OldNames, callback) {
var Res = [];
for (name in OldNames) {
customName(OldNames[name], function(new_name) { Res.push(new_name); });
});
callback(Res);
}
var Names = ['toto', 'tata', 'titi'];
changeNames(Names, function(Names) {
//...
});
Here the loop is over before the first HTTP call, so the Res array is empty.
How can we synchronize this execution?
I know it's not very good to synchronize treatments in nodejs. Do you think it would be better to communicate the names one by one with the client and not building an array?
You can use async.map for that. You pass it your list of names, it will run the getOriginalName function (which you mistakenly called customName, I think) for each name and gather the result, and in the end it will call a function with an array of results:
var http = require('http');
var async = require('async');
function getOriginalName(name, callback) {
var option = {
host:'changename.com',
path: '/'+name,
headers: { 'Content-Type': 'application/json' },
port: 80,
method:'POST'
};
var req = http.request(option, function(res) {
var output = "";
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', function() {
var obj = JSON.parse(output);
callback(null, obj.res);
});
});
req.on('error', function(e) {
callback(e);
});
req.end();
}
function changeNames(OldNames, callback) {
async.map(OldNames, getOriginalName, callback);
}
var Names = ['toto', 'tata', 'titi'];
changeNames(Names, function(err, NewNames) {
console.log('N', NewNames);
});