AWS Lambda return "Internal Server Error" - node.js

My version Node.js 14.x
When using https.request return "Internal Server Error" :
const https = require('https');
exports.handler = async(event) => {
console.log(event);
let dataString = ''
const response = await new Promise((resolve, reject) => {
const { pathParameters } = event;
if (!pathParameters || !pathParameters.id) {
resolve({
statusCode: 400,
body: 'Please provide a id!'
})
}
const options = {
hostname: 'pokeapi.co',
path: `/api/v2/pokemon/${pathParameters.id}`,
port: 443,
method: 'GET',
headers: { 'Content-Type': 'application/json' }
};
const req = https.request(options, function(res) {
res.on('data', chunk => {
console.log(chunk);
dataString += chunk;
});
res.on('end', () => {
resolve({
statusCode: 200,
body: JSON.stringify(JSON.parse(dataString), null, 4)
});
});
});
req.on('error', (e) => {
reject({
statusCode: 500,
body: 'Something went wrong!'
});
});
});
return response
;};
https.get works well :
const https = require('https');
exports.handler = async(event) => {
console.log(event);
let dataString = ''
const response = await new Promise((resolve, reject) => {
const { pathParameters } = event;
if (!pathParameters || !pathParameters.id) {
resolve({
statusCode: 400,
body: 'Please provide a id!'
})
}
const req = https.get(`https://pokeapi.co/api/v2/pokemon/${pathParameters.id}`, function(res) {
res.on('data', chunk => {
console.log(chunk);
dataString += chunk;
});
res.on('end', () => {
resolve({
statusCode: 200,
body: JSON.stringify(JSON.parse(dataString), null, 4)
});
});
});
req.on('error', (e) => {
reject({
statusCode: 500,
body: 'Something went wrong!'
});
});
});
return response;
};
{pathParameters.id} this is the id that I get from the gateway and I need to handle it in a function. I must say right away that this is not because of the quotes in the path and not in the port. There are no errors in the CloudWatch logs. I am connecting lambda function to AWS gateway http.
START RequestId: 86503ade-fd54-400a-bd39-d58cd9d5cc45 Version: $LATEST
2021-07-28T19:21:37.826Z 86503ade-fd54-400a-bd39-d58cd9d5cc45 INFO {
version: '2.0',
routeKey: 'GET /api/schedule/quest/{id}',
rawPath: '/dev/api/schedule/quest/1',
rawQueryString: '',
headers: {
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.5',
'cache-control': 'max-age=0',
'content-length': '0',
host: 'hkh9lnprbf.execute-api.eu-central-1.amazonaws.com',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0',
'x-amzn-trace-id': 'Root=1-6101ae41-697bf7894a7c98d73f84bf31',
'x-forwarded-for': '78.85.49.90',
'x-forwarded-port': '443',
'x-forwarded-proto': 'https'
},
requestContext: {
accountId: '617260961257',
apiId: 'hkh9lnprbf',
domainName: 'hkh9lnprbf.execute-api.eu-central-1.amazonaws.com',
domainPrefix: 'hkh9lnprbf',
http: {
method: 'GET',
path: '/dev/api/schedule/quest/1',
protocol: 'HTTP/1.1',
sourceIp: '78.85.49.90',
userAgent: 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0'
},
requestId: 'DMgqTgDpliAEQzg=',
routeKey: 'GET /api/schedule/quest/{id}',
stage: 'dev',
time: '28/Jul/2021:19:21:37 +0000',
timeEpoch: 1627500097792
},
pathParameters: { id: '1' },
isBase64Encoded: false
}
END RequestId: 86503ade-fd54-400a-bd39-d58cd9d5cc45
REPORT RequestId: 86503ade-fd54-400a-bd39-d58cd9d5cc45 Duration: 3004.50 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 17 MB
2021-07-28T19:21:40.823Z 86503ade-fd54-400a-bd39-d58cd9d5cc45 Task timed out after 3.00 seconds
This is not a solution, but now I see an error in the logs after listening to the answer about increasing the timeout.
2021-07-29T04:59:26.187Z 8536861f-b6e8-46fd-8c9b-93a060be47bb ERROR Invoke Error
{
"errorType": "Error",
"errorMessage": "[object Object]",
"stack": [
"Error: [object Object]",
" at _homogeneousError (/var/runtime/CallbackContext.js:12:12)",
" at postError (/var/runtime/CallbackContext.js:29:54)",
" at done (/var/runtime/CallbackContext.js:58:7)",
" at fail (/var/runtime/CallbackContext.js:70:7)",
" at /var/runtime/CallbackContext.js:106:16",
" at processTicksAndRejections (internal/process/task_queues.js:95:5)"
]
}
I also found a workaround using
http.get(option, function (res) {.....
instead of
http.reguest(option, function (res) {.....

Your Lambda is timing out after the default 3 seconds:
2021-07-28T19:21:40.823Z 86503ade-fd54-400a-bd39-d58cd9d5cc45 Task timed out after 3.00 seconds
You'll need to increase this in either the AWS console (AWS Lambda -> Functions -> function_name -> General configuration -> Edit and set timeout) or via your method of deployment.

Related

Node https request returns Missing or duplicate parameters

Trying to get a token from ADP's API.
const https = require('https')
const fs = require('fs')
require('dotenv').config()
var requestBody = JSON.stringify({
client_id: process.env.ADP_CLIENT_ID,
client_secret: process.env.ADP_CLIENT_SECRET,
grant_type: 'client_credentials',
});
const options = {
hostname: 'accounts.adp.com',
port: 443,
path: '/auth/oauth/v2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': requestBody.length
},
cert: fs.readFileSync('certificate.pem'),
key: fs.readFileSync('private.key'),
agent: false,
}
console.debug(options)
const req = https.request(options, (res) => {
let response = ''
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (chunk) => {
response += chunk
})
res.on('end', ()=>{
console.log('Body: ', JSON.parse(response));
})
}).on("error", (err) => {
console.error("Error: ", err.message);
});
req.write(requestBody)
req.end()
When the script runs, an error is returned from the service:
$ node ./get_token.js
{
hostname: 'accounts.adp.com',
port: 443,
path: '/auth/oauth/v2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': 141
},
cert: <Buffer ... bytes>,
key: <Buffer ... bytes>,
agent: false
}
statusCode: 400
headers: {
'adp-correlationid': 'XXX',
'x-ca-err': '3003103',
'cache-control': 'no-store',
pragma: 'no-cache',
'content-type': 'application/json;charset=UTF-8',
'content-length': '84',
date: 'Wed, 18 Jan 2023 17:50:06 GMT',
connection: 'close',
server: 'ADP API'
}
body: {
error: 'invalid_request',
error_description: 'Missing or duplicate parameters'
}
What am I missing or duplicating?
I needed to correctly serialize the requestBody:
...
const qs = require('querystring');
...
var requestBody = qs.stringify({
client_id: process.env.ADP_CLIENT_ID,
client_secret: process.env.ADP_CLIENT_SECRET,
grant_type: 'client_credentials',
});
which generated the expected response:
{
access_token: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
token_type: 'Bearer',
expires_in: 3600,
scope: 'api'
}

Error when sending https request to ROBLOX API

I'm writing a simple API request to Roblox so I can retrieve the X-CSRF-TOKEN to do POST requests. The issue I'm facing is "Error: socket hang up".
I tried to just run the link in my browser and it displays a JSON table, but when I do the request through node.js it errors out.
const https = require("https")
const options = {
hostname: "groups.roblox.com",
path: "/v1/groups/5307563",
method: "GET",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': '.ROBLOSECURITY=' + cookie
}
}
const request = https.request(options, res => {
res.on('data', data => {
console.log("data received")
})
});
request.on('error', error => {
console.log(error)
})
You need to end the request with request.end().
const https = require("https")
const options = {
hostname: "groups.roblox.com",
path: "/v1/groups/5307563",
method: "GET",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': '.ROBLOSECURITY=' + cookie
}
}
const request = https.request(options, res => {
res.on('data', data => {
console.log("data received")
})
});
request.on('error', error => {
console.log(error)
})
request.end()

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
}
}

How to send post request to iotdata service with authorization from a node js lambda function

I have the following post request that works in insomnia, but am not sure how to send it in node js lambda function, specifically I don't know how to do the authorization.
Here is my setup in insomnia
post request
https://obsf-ats.iot.us-east-1.amazonaws.com/things/esp8266_7F3B95/shadow
json
{
"state" :{
"desired":{
"on": true
}
}
}
auth
What I would do, but don't know where to put the auth, I am also not sure where to put the body of the message. Any help would be greatly appreciated.
const https = require('https')
const data = JSON.stringify({
todo: 'Buy the milk'
})
const options = {
hostname: 'https://obsf-ats.iot.us-east-1.amazonaws.com',
port: 443,
path: '/things/esp8266_7F3B95/shadow',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
process.stdout.write(d)
})
})
req.on('error', error => {
console.error(error)
})
req.write(data)
req.end()
UPDATE: I have tried the following but it error with no console, is there a way to get the request error
var load = JSON.stringify({
state: {
desired: {
on: false,
},
},
});
request(
aws4.sign(
{
hostname: "https://obsf-ats.iot.us-east-1.amazonaws.com",
service: "iotdata",
region: "us-east-1",
method: "POST",
path: "/things/esp8266_7F3B95/shadow",
headers: {
"Content-Type": "application/x-amz-json-1.0",
},
body: load,
},
{
secretAccessKey: "obsf/obsf/x5Hpej0I",
accessKeyId: "obsf",
}
)
);
UPDATE: I am getting the following error and a 403
etaddrinfo ENOTFOUND https://obsf-ats.iot.us-east-1.amazonaws.com
Had to change this from
hostname: 'https://obsf-ats.iot.us-east-1.amazonaws.com',
to this
hostname: 'obsf-ats.iot.us-east-1.amazonaws.com',

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

Resources