Error: socket hang up - Lambda nodejs function http post request - node.js

I have a very simple function in Lambda using Nodejs.
The purpose of that function is to triggered a third party api every 1 minute.
So for that I have setup Cloud Watch Cron based event.
But that Api is throwing this error:
START RequestId: 54d90c9d-0a5b-4e5e-a26a-857d9bb6dd4e Version: $LATEST
2022-08-29T11:11:59.112Z 54d90c9d-0a5b-4e5e-a26a-857d9bb6dd4e ERROR Error: socket hang up
at connResetException (node:internal/errors:692:14)
at TLSSocket.socketOnEnd (node:_http_client:478:23)
at TLSSocket.emit (node:events:539:35)
at endReadableNT (node:internal/streams/readable:1345:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
code: 'ECONNRESET'
It works fine in a simple nodejs code on my local machine.
Here is my Lambda Function code:
const https = require('https');
exports.handler = async (event) => {
var postData = JSON.stringify({
"client_id": "abnbfye9-qtfnf1cj-abhrhzfyf7-m2tup-6x9kk2kc5688",
"client_secret": "fpghfh329-polk80s-ye043465p1yy-45hxnfd874z06",
"inTime": new Date(),
"outTime": new Date()
});
var options = {
hostname: 'example.com',
path: '/api/updateDataLambda',
method: 'POST',
port: 443, // 👈️ replace with 80 for HTTP requests
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiJ0ekpFTlNxcDJXeXh4YlNGbSIsImFjY2Vzc1Rva2VuRXhwIjp7ImRhdGUiOiIyMDIyLTA5LTI4IiwidGltZSI6IjA2OjIwOjQ1IiwidGltZVN0YW1wIjoxNjY0MzQ2MDQ1NjQ2LCJnbXQiOiIrMDAwMCJ9LCJyZWZyZXNoVG9rZW5FeHAiOnsiZGF0ZSI6IjIwMjItMDktMjgiLCJ0aW1lIjoiMDY6MjA6NDUiLCJ0aW1lU3RhbXAiOjE2NjQzNDYwNDU2NDYsImdtdCI6IiswMDAwIn0sImlhdCI6MTY2MTc1NDA0NSwiZXhwIjoxNjYxNzU0MTA1fQ.g1e5S15Q1qxB5_s4j3LFfFf6spU8gwgBUyVNLVuWNWk'
}
};
var 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.write(postData);
req.end();
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
Am I doing something wrong here?

Related

sending http request with proxy ip in node.js

I am trying to send an http get request from a different ip, such as hardcoding the proxy ip to use.
I have a working http get request in node.js:
const https = require('https')
//get access token
let accessToken = await spotifyAuth.getAccessToken();
//create data
const data = JSON.stringify({
offset: 0,
})
//create options data obj
const options = {
hostname: 'api.spotify.com',
path: '/v1/artists/1XqqyIQYMonHgllb1uysL3/albums',
method: 'GET',
headers: {
'Authorization': 'Bearer ' + accessToken,
},
}
const req = https.request(options, res => {
console.log(`proxyiprequest() statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error('proxyiprequest() err=', error)
})
req.write(data)
req.end()
So I'm trying to add an https proxy ip address/port combo I found from here like so:
//create options data obj
const options = {
host: "220.135.165.38",
port: 8080,
hostname: 'api.spotify.com',
path: '/v1/artists/1XqqyIQYMonHgllb1uysL3/albums',
method: 'GET',
headers: {
'Authorization': 'Bearer ' + accessToken,
},
}
Would this method work? If I run the request it errors out like:
proxyiprequest() err= { Error: write EPROTO 18:error:1B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:331:
at WriteWrap.afterWrite [as oncomplete] (net.js:789:14) errno: 'EPROTO', code: 'EPROTO', syscall: 'write' }

Error: getaddrinfo ENOTFOUND error when making an HTTPS/HTTP request

Here's the code of my AWS Lambda function:
console.log('Loading function');
const AWS = require('aws-sdk');
const https = require('https');
const data = JSON.stringify({
secretKey:"someSecretKey",
userType:"someCoolUser",
})
const options = {
hostname: "backend-staging.programmingpathshala.com:8080/rest/admin",
path: '/sendEmailToUsers',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
exports.handler = function(event, context, callback) {
var dataString = '';
const req = https.request(options, function(res) {
res.on('data', chunk => {
dataString += chunk;
});
res.on('end', () => {
callback(null,dataString);
});
});
req.write(data)
req.end();
req.on('error', (e) => {
console.error(e);
});
}
When I test my API using postman it works fine. But when it is called from lambda function I get the following error:
Also, When I run the same API using ngrok and use its link in my lambda function it works then too.
Based on the comments, the options should be:
const options = {
hostname: "backend-staging.programmingpathshala.com",
port: 8080,
path: '/rest/admin/sendEmailToUsers',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}

Invoking Spotify API from lambda function

I need to get data from Spotify API then send the response to the front-end. To avoid CORS issue and to hide key and secret from Spotify, I would like to use Lambda to make the API call then send back the response. To be more precise about my application:
1. FrontEnd > API Gateway
2. API Gateway > Lambda
3. Lambda > Spotify API (request their API to get token)
4. Spotify API > Lambda (token in the response)
5. Lambda > API Gateway
6. API Gateway > FrontEnd
Spotify endpoint is:
https://accounts.spotify.com/api/token?grant_type=client_credentials
Header is:
Content-Type: 'application/x-www-form-urlencoded'
Authorization: 'Basic XXX'
So far I was able to do this using a Lambda function:
const https = require('https');
exports.handler = async (event, context) => {
return new Promise((resolve, reject) => {
const options = {
hostname: 'accounts.spotify.com',
path: '/api/token?grant_type=client_credentials',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic XXX'
}
}
const req = https.request(options, (res) => {
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
resolve('Success');
});
req.on('error', (e) => {
reject(e.message);
});
// send the request
req.write('');
req.end();
});
};
But I can't get the response from the API:
{
"access_token": "YYY",
"token_type": "Bearer",
"expires_in": 3600,
"scope": ""
}
And I don't know how to send the data back to the front-end. Do you have any guidance to achieve what I'm looking for?
Edit: I also tried using axios as suggested:
const axios = require("axios");
module.exports.handler = (event, context, callback) => {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic XXX'
}
axios.post('https://accounts.spotify.com/api/token?grant_type=client_credentials', {}, {
headers: headers
})
.then(function(response) {
console.log(response)
callback(null, response);
})
.catch(function(err) {
console.error("Error: " + err);
callback(err);
});
};
But got the following error:
Response:
{
"errorType": "Error",
"errorMessage": "Request failed with status code 400",
"trace": [
"Error: Request failed with status code 400",
" at createError (/var/task/node_modules/axios/lib/core/createError.js:16:15)",
" at settle (/var/task/node_modules/axios/lib/core/settle.js:17:12)",
" at IncomingMessage.handleStreamEnd (/var/task/node_modules/axios/lib/adapters/http.js:237:11)",
" at IncomingMessage.emit (events.js:215:7)",
" at endReadableNT (_stream_readable.js:1183:12)",
" at processTicksAndRejections (internal/process/task_queues.js:80:21)"
]
}
Thanks to #jarmod and #Ashish Modi, the solution below is working for me:
const axios = require("axios");
const querystring = require('querystring');
module.exports.handler = (event, context, callback) => {
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic XXX'
}
axios.post('https://accounts.spotify.com/api/token?grant_type=client_credentials', querystring.stringify({}), {
headers: headers
})
.then(function(response) {
const res = {
statusCode: 200,
body: (response.data.access_token)
};
callback(null, res);
})
.catch(function(err) {
console.error("Error: " + err);
callback(err);
});
};
try this
const https = require('https');
function hitApi() {
return new Promise((resolve, reject) => {
const options = {
hostname: 'accounts.spotify.com',
path: '/api/token?grant_type=client_credentials',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic XXX'
}
}
https.request(options, (res) => {
res.setEncoding("utf8");
let body = "";
res.on('data', function (chunk) {
body += chunk;
});
res.on("error", err => {
reject(err);
});
res.on('end', function () {
resolve(body);
});
});
});
}
exports.handler = async (event, context) => {
const result = await hitApi();
return result;
};
hope this helps

Getting error on hitting Google Vision Api

const options = {
hostname: 'https://vision.googleapis.com/v1/images:annotate?key=<some key>',
method: 'POST',
headers: {
'Content-Type' : 'application/json'
}
};
const req = http.request(options, (res : any) => {
res.on('data', (chunk : any) => {
console.log(`BODY: ${chunk}`);
});
});
req.on('error', (e) => {
console.log(e)
console.error(`problem with request: ${e.message}`);
});
// Write data to request body
req.write(JSON.stringify(body))
req.end()
I am trying to use one of the google vision feature i.e. Text Detection. But when ever I am hitting that api I am getting this error. I double checked the url and other data.
{ Error: getaddrinfo ENOTFOUND https://vision.googleapis.com/v1/images:annotate?key=<> https://vision.googleapis.
com/v1/images:annotate?key=<key>:80
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:56:26)
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname:
'https://vision.googleapis.com/v1/images:annotate?key=<key>',
host:
'https://vision.googleapis.com/v1/images:annotate?key=<key>',
port: 80 }
This code should work, there are only a couple of changes necessary, for example we'll use the https module rather than the http module.
const https = require('https');
const options = {
hostname: 'vision.googleapis.com',
path: '/v1/images:annotate?key=' + API_KEY,
method: 'POST',
headers: {
'Content-Type' : 'application/json'
}
};
let data = "";
const req = https.request(options, (res: any) => {
res.on('data', (chunk: any) => {
data += chunk;
});
res.on('end', (chunk) => {
console.log(`BODY: ${data}`);
});
});
req.on('error', (e) => {
console.log(e)
console.error(`problem with request: ${e.message}`);
});
// Write data to request body
req.write(JSON.stringify(body))
req.end()
Try modifying the request to:
const options = {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
}
};
const req = http.request(`https://vision.googleapis.com/v1/images:annotate?key=<some key>`, options, (res : any) => {
res.on('data', (chunk : any) => {
console.log(`BODY: ${chunk}`);
});
});
because https://vision.googleapis.com/v1/images:annotate?key=<some key> is a full URL, not a valid hostname.

Node Http Post argument to Spark Job Server

The following curl command works perfectly to call, pass argument and execute my "jobified" spark program
curl 'http://someserver:8090/jobs?appName=secondtest&classPath=Works.epJob&context=hiveContext' -d "inputparms=/somepath1 /somepath2"
Here is the spark program
override def runJob(hive: HiveContext, config: Config):Any = {
var inputParms = config.getString("inputparms").split(" "); //comes from node
var path1 = inputParms.apply(0)
var path2 = inputParms.apply(1)
Instead of the curl command, I need to do a http post in node.js. Here is what I have
var postData = JSON.stringify({
"inputparms": paths
})
var options = {
hostname: 'someserver',
port: 8090,
path: '/jobs?appName=secondtest&classPath=Works.epJob context=hiveContext',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData , 'utf8')
}
};
http.request(options, function(response) {...
Howerever the above script does not work. Am I missing something?
Thanks!
Edit 1:
var myreq = http.request(options, function(response) { ...})
myreq.write(postData);
myreq.end();
I get a parse error
Error: Parse Error
at Error (native)
at Socket.socketOnData (_http_client.js:361:20)
at emitOne (events.js:96:13)
at Socket.emit (events.js:188:7)
at readableAddChunk (_stream_readable.js:177:18)
at Socket.Readable.push (_stream_readable.js:135:10)
at TCP.onread (net.js:542:20) bytesParsed: 2, code: 'HPE_INVALID_CONSTANT' }
The following works for me
var http = require("http");
var options = {
hostname: 'localhost',
port: 8090,
path: '/jobs?appName=test&classPath=spark.jobserver.LongPiJob',
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
};
var req = http.request(options, function(res) {
console.log('Status: ' + res.statusCode);
console.log('Headers: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (body) {
console.log('Body: ' + body);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('stress.test.longpijob.duration=120');
req.end();

Resources