null response when calling lambda - node.js

My lambda function is returning a null response and I'm not sure why. When I change 'res.body' to 'res.statusCode' I get the status code 200 as expected. I've checked the logs of my api call and see that there are no issues with the details I am passing (also confirmed using a curl command. Any ideas?
const https = require('https');
function getRequest() {
const options = {
host: 'vehimgd36c3.execute-api.ap-southeast-2.amazonaws.com',
path: '/callinglink',
method: 'GET',
headers: {
'link': 'https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.Function.html'
}
}
return new Promise(function(resolve, reject) {
https.get(options, (res) => {
resolve(res.body)
}).on('error', (e) => {
reject(Error(e))
})
})
}
exports.GetReturnMessage = async (event) => {
try {
const result = await getRequest();
console.log(result)
return {
"sessionState": {
"dialogAction": {
"type": "Close"
},
"intent": {
"confirmationState": "Confirmed",
"name": "FinalResponse",
"state": "InProgress",
},
},
"messages": [
{
"contentType": "CustomPayload",
"content": result
},
]
};
} catch (error) {
console.log('Error is: ️', error);
return {
statusCode: 400,
body: error.message,
};
}
};

If you check how to use lambda and apigateway. apigateway expects the lamba function to return a response with the structure Read here
var response = {
"statusCode": 200,
"body": "{\n \"TotalCodeSize\": 104330022,\n \"FunctionCount\": 26\n}"
}
in that case you could try returning your object as follows:
exports.GetReturnMessage = async (event) => {
try {
const result = await getRequest();
console.log(result)
const response = {
"sessionState": {
"dialogAction": {
"type": "Close"
},
"intent": {
"confirmationState": "Confirmed",
"name": "FinalResponse",
"state": "InProgress",
},
},
"messages": [
{
"contentType": "CustomPayload",
"content": result
},
]
};
return {
"statusCode": 200,
"body": JSON.stringify(response)
}
} catch (error) {
console.log('Error is: ️', error);
return {
statusCode: 400,
body: error.message,
};
}
}

Related

How to Get the Particular Fields From the response which is in json format

I wanted to extract the repoNames and their Topics from the response body
and the body contains reponames, ids, topics...
which is the github api output
and wanted to extract the fields that are only required from the output body of the api
{
const request = require('request');
// configuration for the url generation
const perPages = 100;
const startPage = 1;
const endPage = 17;
const url = 'https://api.github.com/orgs/organasationName/repos?per_page=%perPages%&page=%page%';
// define a asyncronous call for one url
async function callOneUrl(url) {
// local options for each url
const options = {
'method': 'GET',
'url': url, //To get all the users data from the repos
'headers': {
'Accept': 'application/vnd.github.mercy-preview+json',
'Authorization': 'Bxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'User-Agent': 'nxxxxxxxxxxxx'
}
}
return new Promise((resolve, reject) => {
request(options, function (error, response) {
if (error) return reject(error);
resolve(response);
});
});
}
// call each url with a for loop
(async () => {
for (let i = startPage; i <= endPage; i++) {
// using the await statement to get the resolved value of the Promise instance or catch the error
try {
var response = await callOneUrl(url.replace('%perPages%', perPages).replace('%page%', i));
// handle response here
console.log(response.body);
} catch (error) {
// handle errors here
throw new Error(error);
}
}
})()
the response body of the api is in json format
the response of the above code is like
{
{ /////output of the above code////
"id": 1 xxxxx '
"name": hvvXxxxx,
"org_id": 1 xxx,
.
.
.
"topics": ["hue", "right", "left"]
}, {
"id": 2 xxxxx '
"name": hvvXxxxxwww,
"org_id": 1 xxx,
.
.
.
"topics": ["hue", "right", "go"]
}, {
"id": 3 xxxxx '
"name": hvvXxxxxttt,
"org_id": 1 xxx,
.
.
.
"topics": ["hue", "right", "left", "good"]
}
}
You could simply use .map to get the required properties like this
const response = [{
"id": "1xxxxx",
"name": "hvvXxxxx",
"org_id": "1xxx",
"topics": ["hue", "right", "left"]
},
{
"id": "2xxxxx",
"name": "hvvXxxxxwww",
"org_id": "1xxx",
"topics": ["sss", "sds"]
}
];
console.log(response.map(i => ({
"org_id": i.org_id,
"topics": i.topics
})));
You can also try lodash lib for that.
Pick loadash
e.g
const response = [{
"id": "1xxxxx",
"name": "hvvXxxxx",
"org_id": "1xxx",
"topics": ["hue", "right", "left"]
},
{
"id": "2xxxxx",
"name": "hvvXxxxxwww",
"org_id": "1xxx",
"topics": ["sss", "sds"]
}
];
const expectedArr = response.map(i => _pick(i, ['name', 'topics', 'etc...']))
Thanks

"data" field not populated in axios response from express server

I am trying to access data from a nodejs server using Express on the server and Axios on the backend.
This is the endpoing I am trying to reach: http://gentle-bastion-49098.herokuapp.com/api/filters
As you can see it actually returns data when you navigate to it. But when I try to access it using the following code:
const BASE_URL = 'http://gentle-bastion-49098.herokuapp.com/api'
function getFilterData () {
const url = `${BASE_URL}/filters`
return axios.get(url)
}
getFilterData()
.then(function (response) {
console.log('filter', response)
})
.catch(err => {
alert('Could not get filters ' + err.message.toString())
})
I get this response with the "data" field being unpopulated where I'm expecting it to contain the JSON you see in the URL.
{
"data": "",
"status": 200,
"statusText": "OK",
"headers": {},
"config": {
"url": "http://gentle-bastion-49098.herokuapp.com/api/filters",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*"
},
"transformRequest": [null],
"transformResponse": [null],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1
},
"request": {}
}
Here is the back end code
const express = require('express');
const app = express();
const async = require('async');
const request = require('request');
const http = require('http');
const EventSource = require('eventsource');
const port = process.env.PORT || 8080;
const bodyParser = require('body-parser');
const jsonParser = bodyParser.json()
app.get('/api/filters', function(req, res) {
let filtersResponse = {
"ID": "CONV_DATA#IVA",
"ApplicationName": "InterationsView",
"Type": "FILT_DETAIL",
"filters": [{
"Name": "ChannelType",
"Values": uniqueFilters.ChannelType,
},
{
"Name": "sessionType",
"Values": uniqueFilters.sessionType,
},
{
"Name": "Direction",
"Values": uniqueFilters.Direction,
},
{
"Name": "Status",
"Values": uniqueFilters.Status,
},
{
"Name": "statusReason",
"Values": uniqueFilters.statusReason,
},
],
"minDuration": uniqueFilters.minDuration,
"maxDuration": uniqueFilters.maxDuration,
"minData": "2019-08-29T22:28:47.029UTC",
"maxDate": "2019-08-29T22:28:49.578UTC"
};
// Respond with filters
res.json(filtersResponse);
});
Any ideas as to why the data field is unpopulated even though when accessed through browser or postman it returns the desired data? Is it a problem with the back end or the way the request is being made? Thanks.
I have also enabled cross-orgin resource sharing on my browser. Not doing so results in an error
I am not clear whether you are not getting axios response or response from your node server. If you have problem in getting axios response here is the code.
I have used request npm for making a get request.
const request = require('request');
apiUrl = "http://gentle-bastion-49098.herokuapp.com/api/filters"
request.get(
{
url: apiUrl,
json: true
},
function (error, response, body) {
if (error) {
console.log("Error Occurred :", error);
}
console.log("Response Data :", body)
}
);
The above code will give you response as :
{
"ID":"CONV_DATA#IVA",
"ApplicationName":"InterationsView",
"Type":"FILT_DETAIL",
"filters":[
{
"Name":"ChannelType",
"Values":[
"Phone",
"Web-Chat",
"Google-Assistant"
]
},
{
"Name":"sessionType",
"Values":[
"nlu-voice",
"nlu-text"
]
},
{
"Name":"Direction",
"Values":[
"In"
]
},
{
"Name":"Status",
"Values":[
"Complete",
"Started"
]
},
{
"Name":"statusReason",
"Values":[
"END"
]
}
],
"minDuration":9.7,
"maxDuration":154.2,
"minData":"2019-08-29T22:28:47.029UTC",
"maxDate":"2019-08-29T22:28:49.578UTC"
}
which is same as what you get in browser when you visit the link http://gentle-bastion-49098.herokuapp.com/api/filters
If you are using axios the code will be :
const axios = require('axios');
apiUrl = "http://gentle-bastion-49098.herokuapp.com/api/filters"
axios.get(apiUrl)
.then(function (response) {
console.log("Response Data :", response.data);
})
.catch(function (error) {
console.log("Error Occurred :", error);
})
and it will give same response as above.
Even your written code is giving response :
Try with these changes:
getFilterData().then(response => {
console.log('filter', response.data)
})
.catch(err => {
alert('Could not get filters ' + err.message.toString())
})
In your server code, send the response back to client using res.send() as shown below:
app.get('/api/filters', function(req, res) {
let filtersResponse = {
"ID": "CONV_DATA#IVA",
"ApplicationName": "InterationsView",
"Type": "FILT_DETAIL",
"filters": [{
"Name": "ChannelType",
"Values": uniqueFilters.ChannelType,
},
{
"Name": "sessionType",
"Values": uniqueFilters.sessionType,
},
{
"Name": "Direction",
"Values": uniqueFilters.Direction,
},
{
"Name": "Status",
"Values": uniqueFilters.Status,
},
{
"Name": "statusReason",
"Values": uniqueFilters.statusReason,
},
],
"minDuration": uniqueFilters.minDuration,
"maxDuration": uniqueFilters.maxDuration,
"minData": "2019-08-29T22:28:47.029UTC",
"maxDate": "2019-08-29T22:28:49.578UTC"
};
// Respond with filters
res.send(
filtersResponse
)
});

Variable not refreshing on re-run. How do I pass down the variable?

I want to pass down the variables I create when hitting the /pay route to the /success_api route. Namely I need to pass down 'content', 'productSelectTotal', 'productSubTotal', and 'shipping'. When I trigger /pay the first time, it sets content which is then passed down when I am redirected to '/success', however on all subsequent requests, the value of content, productSelectTotal, productSubTotal, and shipping in the 'success_api' get function remain the same.
Any ideas how to make sure they are being refreshed every time the value of the variables in the parent function is updated?
router.post('/pay', (req, res, next) => {
fs.readFile('ProductDB.json', function (error, data) {
if (error) {
res.status(500).end()
} else {
const productsJson = JSON.parse(data)
console.log(req.body.items)
let content = [];
let productSelect = req.body.items.map(product => {
const itemJson = productsJson.find(function (i) {
return i.productName === product.productName
}).variations.find(function (i) {
return i.id === product.id
})
product.id != null ?
content.push({
// PUSH TO CONTENT HERE
"name": product.productName,
"sku": product.id,
"price": itemJson.variationPrice / 100,
"currency": "USD",
"quantity": product.qty
}) :
false
})
let tariffObj = {
"uk": 3.6,
"us": 11.6,
"rest-of-world": 11.6,
"eu": 8.2
}
let postalCategory = req.body.postalCategory
let postalTarrif = tariffObj[postalCategory]
let shipping = postalTarrif;
let productSelectPrices = content.map(item => item.price * item.quantity);
let productSelectTotal = productSelectPrices.reduce((acc, val) => acc + val, shipping).toFixed(2)
let productSubTotal = productSelectPrices.reduce((acc, val) => acc + val, 0).toFixed(2)
const create_payment_json = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": `http://localhost:3000/success`,
"cancel_url": `http://localhost:3000/cancel`
},
"transactions": [{
"item_list": {
"items": content
},
"amount": {
"currency": "USD",
"total": productSelectTotal,
"details": {
"subtotal": productSubTotal,
"shipping": shipping
}
},
"description": "first tea added to the store"
}]
}
paypal.payment.create(create_payment_json, function (error, payment) {
if (error) {
throw error;
} else {
console.log("Create Payment Response");
console.log(payment);
for (let i = 0; i < payment.links.length; i++) {
if (payment.links[i].rel === "approval_url") {
let redirectURL = payment.links[i].href
res.json({
redirectUrl: redirectURL
})
}
}
}
});
/*
After creating the response the user is redirected to paypal, where they enter their payment information after which they are returned to the website where the / success_api call is made
*/
router.route('/success_api').get((req, res) => {
//CONTENT NOT UPDATED WITHIN THIS FUNCTION ON RE - RUNS
console.log('re routed')
const payerId = req.query.PayerID
const paymentId = req.query.paymentId
const execute_payment_json = {
"payer_id": payerId,
"transactions": [{
"item_list": {
"items": content
},
"amount": {
"currency": "USD",
"total": productSelectTotal,
"details": {
"subtotal": productSubTotal,
"shipping": shipping
}
}
}]
}
paypal.payment.execute(paymentId, execute_payment_json, function (error, payment) {
if (error) {
console.log(error.response);
res.json({
message: 'payment error'
})
} else {
console.log(JSON.stringify(payment));
res.json({
message: 'Payment Successful'
})
}
});
})
}
})
})

How do i get textDetection and LabelDetection with NodeJs?

const results = await visionClient.labelDetection(imageUri).safeSearchDetection(imageUri);
i am trying to get an image response with cloud vision.
Below is an example of code for an HTTPS Cloud Function that will do the OCR (i.e. text detection) of an image stored in Firebase Storage. You would, for example, call it from your app after you have uploaded an image to Firebase Storage (in the gs://myproject.com/imgtoocr/ bucket), by passing the image name in the body of the HTTP Request.
....
const vision = require('#google-cloud/vision');
const client = new vision.ImageAnnotatorClient();
exports.imageOCR = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const imageFilename = req.body.imageFilename;
let result;
return client
.documentTextDetection(
'gs://myproject.com/imgtoocr/' + imageFilename
)
.then(results => {
const blocks = results[0].fullTextAnnotation.pages[0].blocks;
blocks.forEach(blockDetail => {
blockDetail.paragraphs.forEach(paragraph => {
//Here you build the result you want to send back
});
});
return {
result: result
};
})
.then(ocrResult => {
return res.status(200).json(ocrResult);
})
.catch(err => {
console.error('ERROR:', err);
res.status(400).send(err);
});
});
});
You will find more info and examples (in particular for Label Detection) in the following documentation for node.js:
https://cloud.google.com/vision/docs/ocr-tutorial
https://cloud.google.com/vision/docs/detecting-labels
https://cloud.google.com/nodejs/docs/reference/vision/0.19.x/
Solved it this way for version 0.21.0
import * as vision from '#google-cloud/vision';
const visionClient = new vision.ImageAnnotatorClient();
const request = {
"image": {
"source": {
"imageUri": imageUri
}
},
"features": [
{
"type": "FACE_DETECTION"
},
{
"type": "LABEL_DETECTION"
},
{
"type": "SAFE_SEARCH_DETECTION"
},
{
"type": "WEB_DETECTION"
},
{
"type": "CROP_HINTS"
},
{
"type": "IMAGE_PROPERTIES"
},
{
"type": "DOCUMENT_TEXT_DETECTION"
},
{
"type": "TEXT_DETECTION"
},
{
"type": "LOGO_DETECTION"
},
{
"type": "LANDMARK_DETECTION"
},
{
"type": "TYPE_UNSPECIFIED"
},
// Other detection types here...
]
};
return await visionClient.annotateImage(request).then((res) => {
console.log(JSON.stringify(res));
});

Cannot assign to read only property '_id'

get Error Cannot assign to read only property '_id' when insert data in mongodb using node js
Cannot assign to read only property '_id' of
{"Diagnosis":"vvvvv",
"Treatment":[{
"name":"treatment1",
"SubTreatment":[{
"name":"subtreatment1",
"SubTreatment2" : [{
"name":"subtreatmentexp1",
"$$hashKey":"object:27","Name":"vvvvv"
}],
"$$hashKey":"object:22","Name":"vvvvv"
}],
"$$hashKey":"object:12",
"Name":"vvvvv"
}
]}
please help me to solve this error
my code is
app.post('/post', function (req, res) {
var diagnosis;
var obj = req.headers['data'];
var temp = JSON.parse(obj)
console.log("Received body data:");
console.log(obj);
MongoClient.connect(url, function (err, db) {
assert.equal(null, err);
insertDocument(temp, db, function () {
db.close();
});
});
var insertDocument = function (obj, db, callback) {
try {
console.log(obj);
db.collection('diagnosis').remove();
db.collection('diagnosis').insertOne(obj, function (err, result) {
assert.equal(err, null);
console.log("Inserted a document into the Diagnosis collection.");
callback();
});
res.send("Inserted a document into the Diagnosis collection.");
} catch (err) {
console.log(err);
}
};
})
my function to call API is
$scope.post = function () {
var diagnosis = $scope.Treatments;
var httpRequest = $http({
method: 'POST',
url: '/post',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'data': JSON.stringify($scope.Treatments)
},
}).success(function (data, status) {
});
};
Treatments array....
$scope.Treatments =
{
Diagnosis: '',
Treatment: [
{
name: 'treatment1',
SubTreatment: [
{
name: 'subtreatment1',
SubTreatment2: [{ name: 'subtreatmentexp1' }]
}
],
}
]
};
Generated JSON to insert data is
{
"Diagnosis": "sss",
"Treatment": [
{
"name": "treatment1",
"SubTreatment": [
{
"name": "subtreatment1",
"SubTreatment2": [
{
"name": "subtreatmentexp1",
"$$hashKey": "object:27",
"Name": "sss"
}
],
"$$hashKey": "object:22",
"Name": "sss"
}
],
"$$hashKey": "object:12",
"Name": "sss"
}
]
}

Resources