"data" field not populated in axios response from express server - node.js

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

Related

null response when calling lambda

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

Mongodb Schema issue

Here i am using Nodejs application to get JSON response from external API.I need to capture few key-value pair of this response and need to save it MongoDB.
I am getting the response properly, but i am unable to save the data in database.
Requirement:
Each time i get this response from External server , i need to save it in table by rewriting any documents if already exists in this collection. Here i have nearly 7 array items in json response , i need to save corresponding key value pair from all of the items automatically .
Model:
var mongoose = require('mongoose');
const getAllUsersDataSchema = new mongoose.Schema({
userRefID:[] ,
userName:[],
divisionId: [{}],
divisionName:[{}],
emailId :[{}],
})
module.exports = getAllUsers = mongoose.model('getAllUsers',getAllUsersDataSchema );
**API Call where i am capturing external API response:**
const express = require('express');
const router = express.Router();
const request = require('request');
const config = require('../config');
const fs = require('fs');
const getAllUsers = require ('../db/getAllUsersListmodel');
var mongoose = require('mongoose');
mongoose.connect ('mongodb://localhost/testdb',{ useUnifiedTopology: true , useNewUrlParser: true });
router.get('/', (req, res) => {
// token in session -> get user data and send it back to the Angular app
var data =fs.readFileSync('../teamlist.txt', {encoding:'utf8'} )
console.log(data);
if (data) {
request(
{
method: 'GET',
url: 'https://api.mypurecloud.com/api/v2/users',
headers: {
'Authorization': 'Bearer ' + data
}
},
// callback
(error, response, body) => {
let userInfoResponse = JSON.parse(body);
res.send(userInfoResponse);
console.log(userInfoResponse.entities.length)
console.log(userInfoResponse.entities[0].division.id)
getAllUsers.create({
userRefID : userInfoResponse.entities.id,
userName: userInfoResponse.entities.name,
divisionId: userInfoResponse.entities.division.id,
divisionName:userInfoResponse.entities.division.name,
emailId:userInfoResponse.entities.primaryContactInfo.address
}, (error,post)=>{
console.log(error,post);
});
}
);
}
// no token -> send nothing
else {
res.send("Token Not Present - Kindly login in back");
}
//console.log(req.session.token);
});
Data is saving in DB but not getting any array data saved in to it.
{
"_id" : ObjectId("5fd998d61439a434983702cd"),
"userRefID" : [ ],
"userName" : [ ],
"__v" : 0
}
This is exact API JSON response i am trying to save it in DB and use it for future references:
{
"entities": [
{
"id": "07f426ff-506f-4e5e-afdb-2c7397edac61",
"name": "EPS Purecloud Support",
"division": {
"id": "36852a81-ad7f-4c71-a1cd-7f431c05179f",
"name": "",
"selfUri": "/api/v2/authorization/divisions/36852a81-ad7f-4c71-a1cd-7f431c05179f"
},
"chat": {
"jabberId": "5dcc25e1db8c7e19238a287d#cognizant3.orgspan.com"
},
"email": "eps#genesys.com",
"primaryContactInfo": [
{
"address": "eps#genesys.com",
"mediaType": "EMAIL",
"type": "PRIMARY"
}
],
"addresses": [],
"state": "active",
"username": "eps#genesys.com",
"version": 3,
"acdAutoAnswer": false,
"selfUri": "/api/v2/users/07f426ff-506f-4e5e-afdb-2c7397edac61"
},
{
"id": "c5ce06dc-6265-4d16-be18-f5fc5a918295",
"name": "Generic",
"division": {
"id": "36852a81-ad7f-4c71-a1cd-7f431c05179f",
"name": "",
"selfUri": "/api/v2/authorization/divisions/36852a81-ad7f-4c71-a1cd-7f431c05179f"
},
"chat": {
"jabberId": "5ebab3dba6686314f6913b98#cognizant3.orgspan.com"
},
"email": "integration-generic-a03293c0-945d-11ea-a64c-ebeb45b9d295#webhook.com",
"primaryContactInfo": [
{
"address": "integration-generic-a03293c0-945d-11ea-a64c-ebeb45b9d295#webhook.com",
"mediaType": "EMAIL",
"type": "PRIMARY"
}
],
"addresses": [],
"state": "active",
"username": "integration-generic-a03293c0-945d-11ea-a64c-ebeb45b9d295#webhook.com",
"version": 2,
"acdAutoAnswer": false,
"selfUri": "/api/v2/users/c5ce06dc-6265-4d16-be18-f5fc5a918295"
},
{
/** 3rd User *********/
}
{
/** 4th User *********/
}
],
"pageSize": 25,
"pageNumber": 1,
"total": 7,
"firstUri": "/api/v2/users?pageSize=25&pageNumber=1",
"selfUri": "/api/v2/users?pageSize=25&pageNumber=1",
"lastUri": "/api/v2/users?pageSize=25&pageNumber=1",
"pageCount": 1
}
Entities is an array of objects, but you are trying to refer to its properties as an object:
userRefID : userInfoResponse.entities.id, // but "entities": [ {"id":"...", "name":"..."} ],
userName: userInfoResponse.entities.name,
You have to collect the data in a loop, and only then insert it into the database:
const usersArray = userInfoResponse.entities.map(el => ({
userRefID : el.id,
userName: el.name,
divisionId: el.division.id,
divisionName: el.division.name,
emailId: el.primaryContactInfo[0].address
}));
getAllUsers.insertMany(usersArray)

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

Null value in model.findById when I make a get request [mongodb]

Problem
Hi dev,
I have the problem that when I try to make a get request to the series by id it shows me null.
I have noticed from the Atlas Mongos platform that I created the collection but it does not show me the data, only the structure of the scheme shows me
Function.js
const fs = require('fs');
const fetch = require('node-fetch');
const BASE_URL = " http://localhost:8081/api/v1/"
async function getSeries() {
return new Promise((resolve , reject) =>{
setTimeout(() => {
const res = require('./simple_database/series/1.json' , 'utf8');
resolve(res)
}, 1000);
})
}
module.exports = {
getSeries
}
Router
The route allseries allows me to access all the content. What I want to do is pass that content to the SeriesModel, maybe it is there where I have the problem that the data is not being inserted correctly.
In the route series/:id is where the null value is returning to me
const express = require('express');
const router = express.Router();
const f = require('./function');
const SeriesModel = require('./models/series');
router.get('/allseries', (req, res) => {
f.getSeries().then((series) =>{
res.status(200).json({
series
})
}).then((doc) =>{
SeriesModel.insertMany(doc , function(err , docs){
if(err){
console.error(err)
}else{
console.log(docs);
console.info('%d serie were successfully stored.', docs.length);
}
})
})
});
router.get('/series/:id' , (req , res , next) =>{
const id = req.params.id;
SeriesModel.findById(id)
.exec()
.then((doc) =>{
console.log("From database " , doc);
res.status(200).json(doc)
}).catch((err) =>{
console.error(err);
res.status(500).json({error: err})
})
})
module.exports = router;
Model/series.js
const mongoose = require('mongoose');
const serieSchema = mongoose.Schema({
"_id": {
"$oid": {
"type": "ObjectId"
}
},
"series_id": {
"type": "String"
},
"aggregateRating": {
"reviewCount": {
"type": "Number"
},
"ratingCount": {
"type": "Number"
},
"#type": {
"type": "String"
},
"ratingValue": {
"type": "Number"
}
},
"episodes": {
"1x": {
"07 Ghost": {
"type": [
"Mixed"
]
}
}
},
"metadata": {
"description": {
"type": "String"
},
"url": {
"type": "String"
},
"image": {
"type": "String"
},
"type": {
"type": "String"
},
"id": {
"type": "String"
},
"name": {
"type": "String"
}
},
"1x": {
"07 Ghost": {
"type": [
"Mixed"
]
}
}
});
module.exports = mongoose.model("cr_series" , serieSchema);
It is because findById takes it's parameter in form of object like this
SeriesModel.findById({_id:id})
You need to tell your query to which json object you want to match your incoming object.

API.ai Actions on Google - Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field."

This error is similar to what I asked here, but this time it's with NodeJs client.
I am trying to find directions to a location. As soon as the intent is triggered on my webhook, I am calculating the directions using GoogleMapAPI. But before it can finish and send a response, I receive the error on my Actions Console. I checked total response time and it is less than 2 seconds which is less than 5 seconds timeout by Google.Where I am wrong???
My API.ai Intent
Using express.js with Action-on-Google Node Client
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const intentHandler = require('./intent_handler')
const app = express();
app.use(bodyParser.json());
const ApiAiAssistant = require('actions-on-google').ApiAiAssistant;
// Create functions to handle requests here
....
....
const DIRECTION_INTENT = 'action_direction';
function MyAssistant(req, res) {
const assistant = new ApiAiAssistant({request: req, response: res});
assistant.handleRequest(responseHandler(assistant));
}
function responseHandler (assistant) {
// intent contains the name of the intent you defined in the Actions area of API.AI
let intent = assistant.getIntent();
switch (intent) {
case WELCOME_INTENT:
...
break;
case WELCOME_FALLBACK_PERMISSION_INTENT:
...
break;
case DIRECTION_INTENT:
console.log(">>>>>>>DIRECTION_INTENT<<<<<<<");
intentHandler.directionIntent(assistant);
break;
}
}
app.post('/', function (req, res) {
MyAssistant(req, res);
});
app.listen(8080, function () {
console.log('app listening on port 8080!')
});
Handler Code
'use strict';
const speech = require("./speech_template");
const direction = require("./directionModule");
const intent_handler = {
'welcomeIntent': function (assistant) {
.....
},
'welcomeFallbackPermissionIntent': function (assistant) {
.....
},
'directionIntent':function (assistant) {
console.log('direction intent');
direction.getDirectionWithSavedAddress(function (response) {
assistant.ask(response);
});
}
};
module.exports = intent_handler;
Direction Extraction --- ERROR comes on Action Console before this get finished
'use strict';
const striptags = require('striptags');
const speech = require("./speech_template");
let googleMapsClient = require('#google/maps').createClient({
key: global.GOOGLE_DIRECTION_KEY
});
const directionModule = {
'getDirectionWithSavedAddress': function (eventCallback) {
let myAdd = <From Saved Data>;
if (myAdd === undefined) {
console.log("error......");
}
let destination = <From Saved Data>;
this.getDirectionWithAddress(myAdd, destination, function (dir) {
....
if(SUCCESS){
eventCallback(`<speak> ${steps} </speak>`);
}else{
eventCallback(`<speak> ${speech.ERROR_DIRECTIONS} </speak>`);
}
});
},
'getDirectionWithAddress': function (add1, add2, eventCallback) {
let dir = {};
googleMapsClient.directions({
origin: add1,
destination: add2,
mode: "driving",
departure_time: "now"
}, function (err, response) {
if (!err) {
console.log(response.json.routes[0]);
....
....
....
} else {
console.log(`Error --> ${err.toString()}`);
....
}
eventCallback(dir);
});
}
};
module.exports = directionModule;
UPDATE
I am running the code locally via WebStorm and exposing webhook via port forwarding using ngrok.
Update2
BAD REQUEST 400
{
"originalRequest": {
"source": "google",
"version": "2",
"data": {
"isInSandbox": true,
"surface": {
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
}
]
},
"inputs": [
{
"rawInputs": [
{
"query": "get me there",
"inputType": "VOICE"
}
],
"arguments": [
{
"rawText": "get me there",
"textValue": "get me there",
"name": "text"
}
],
"intent": "actions.intent.TEXT"
}
],
"user": {
"locale": "en-US",
"userId": "<uID>"
},
"device": {},
"conversation": {
"conversationId": "<cID>",
"type": "ACTIVE",
"conversationToken": "[\"_actions_on_google_\",\"defaultwelcomeintent-followup\"]"
}
}
},
"id": "<ID>",
"timestamp": "2017-09-12T17:08:10.321Z",
"lang": "en",
"result": {
"source": "agent",
"resolvedQuery": "get me there",
"speech": "",
"action": "action_direction",
"actionIncomplete": false,
"parameters": {},
"contexts": [
{
"name": "_actions_on_google_",
"parameters": {},
"lifespan": 99
},
{
"name": "google_assistant_input_type_voice",
"parameters": {},
"lifespan": 0
},
{
"name": "actions_capability_audio_output",
"parameters": {},
"lifespan": 0
},
{
"name": "defaultwelcomeintent-followup",
"parameters": {},
"lifespan": 4
}
],
"metadata": {
"intentId": "<iID>",
"webhookUsed": "true",
"webhookForSlotFillingUsed": "false",
"nluResponseTime": 15,
"intentName": "DirectionIntent"
},
"fulfillment": {
"speech": "",
"messages": [
{
"type": 0,
"speech": ""
}
]
},
"score": 1
},
"status": {
"code": 200,
"errorType": "success"
},
"sessionId": "<sID>"
}
This looks like before my callback is finished, my webhook is sending empty response to Google Actions.
Why is this happening and How to resolve it?????
The problem lies in how your directionIntent() function calls, and handles the result of, your getDirectionWithSavedAddress() function. It expects getDirectionWithSavedAddress() returns a function, when it does not. Instead, getDirectionWithSavedAddress() expects to send its results to a callback.
So after it makes its call to getDirectionWithAddress(), the function ends, returning nothing. This "nothing" is sent to assistant.ask(), which returns that to Google's server. This is an invalid response, so you're getting the error.
Fixing this should be straightforward. You need to call getDirectionWithSavedAddress() with a callback function. Inside this function you should call assistant.ask() with the value sent to the callback.
So directionIntent() might look something like
'directionIntent':function (assistant) {
console.log('direction intent');
direction.getDirectionWithSavedAddress( function( msg ){
assistant.ask( msg );
} );
}
Updated
This line makes no sense:
assistant.handleRequest(responseHandler(assistant));
The assistant.handleRequest() function is supposed to be passed a Map of Intent names to functions to call to handle the event. You're doing this manually in the responseHandler() function and you're not returning a Map. Since you're not returning a Map, it fails when trying to do the handleRequest() and generates the error "Action Error: Request handler can NOT be empty".
You can fix this by just calling responseHandler(assistant) and not dealing with handleRequest() at all. Or you can create the map that handleRequest() is expecting and get rid of responseHandler() completely.

Resources