Querying Google Place API for a dialogflow response - javascript

I am trying to query Google Place API for details in order to display a map (by obtaining first coordinates) and location information (address) as a chatbot response. I have written this quote, but I am have having problems with the Google Place API response. Appreciate any help available.
var path1 = `/maps/api/place/details/json?placeid=${placeID}&fields=name,formatted_address,geometry&key=${googleAPI}`;
details = getPlace(path1);
console.log('details: ' + details); //debug statement
function getPlace (path1) {
const host = 'https://maps.googleapis.com';
var url = host + path1;
var data = null;
return new Promise(function(resolve, reject) {
request (url, function (err,response,body) {
if(!err){
try{
data = JSON.parse(body);
resolve(data);
}catch (err) {
console.error('parsing error');
reject('Error during parsing of data: ' + err.message);
}
} else {
console.error('request error');
reject('Unable to get data. Statuscode: ' + response.statusCode);
}
});
});
}
The response I am getting from Firebase is :
dialogflowFirebaseFulfillment details: [object Promise]
when I try the URL in browser, I am getting a proper response
https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJJ0JHF9A3zDERwazNPMoMKAg&fields=name,formatted_address,geometry&key=API-Key
{
"html_attributions" : [],
"result" : {
"formatted_address" : "Level 1, Smart Banking Area Menara Citibank, 165, Jalan Ampang, Kuala Lumpur, 50450 Kuala Lumpur, Wilayah Persekutuan Kuala Lumpur, Malaysia",
"geometry" : {
"location" : {
"lat" : 3.1600754,
"lng" : 101.717633
},
"viewport" : {
"northeast" : {
"lat" : 3.161558980291502,
"lng" : 101.7188249302915
},
"southwest" : {
"lat" : 3.158861019708498,
"lng" : 101.7161269697085
}
}
},
"name" : "Citibank Malaysia - Kuala Lumpur"
},
"status" : "OK"
}
Not sure what is the problem here, anyone able to help?

It may be because you are not awaiting the Promise in getPlace() to resolve before continuing with your code.
Try making the function you are calling getPlace() from async and using await when calling the function. For example:
async function parentFunction() {
var path1 = `/maps/api/place/details/json?placeid=${placeID}&fields=name,formatted_address,geometry&key=${googleAPI}`;
details = await getPlace(path1);
console.log('details: ' + details);
}
Here's a good post that explains async code and how to deal with it

Related

unspecified index when searching data with firebase cloud function on nested object running nested Query

I'm using fire-base to retrieve nested data of users node, and while running query I'm facing this issue fetching data from fire-base database.
Consider adding ".indexOn": "userId" at
/users/YJdwgRO08nOmC5HdEokr1NqcATx1/following/users to your security
rules for better performance.
Database Structure:
"users" : {
"1vWvSXDQITMmKdUIY7SYoLA1MgU2" : {
"userEmail" : "test2kawee#gmail.com",
"userId" : "1vWvSXDQITMmKdUIY7SYoLA1MgU2",
"userName" : "Malik Abdul Kawee",
"userPhoneNumber" : "",
"userProfileImage" : "https://pbs.twimg.com/profile_images/1018741325875867648/ZnKeUiOJ_400x400.jpg"
},
"YJdwgRO08nOmC5HdEokr1NqcATx1" : {
"following" : {
"1vWvSXDQITMmKdUIY7SYoLA1MgU2" : {
"currentFollowingUserId" : "YJdwgRO08nOmC5HdEokr1NqcATx1",
"userEmail" : "test2kawee#gmail.com",
"userId" : "1vWvSXDQITMmKdUIY7SYoLA1MgU2",
"userName" : "Malik Abdul Kawee",
"userPhoneNumber" : "",
"userProfileImage" : "https://pbs.twimg.com/profile_images/1018741325875867648/ZnKeUiOJ_400x400.jpg"
}
},
"userEmail" : "test2atif#gmail.com",
"userId" : "YJdwgRO08nOmC5HdEokr1NqcATx1",
"userName" : "Atif AbbAsi",
"userPassword" : "test123",
"userPhoneNumber" : "",
"userProfileImage" : "http://paperlief.com/images/enrique-iglesias-body-workout-wallpaper-4.jpg"
}
}
Database Rules:
"users": {
".indexOn": ["userId","currentFollowingUserId",".value"],
"$userId": {
"following": {
//"$userId": {
".indexOn": ["userId","currentFollowingUserId",".value"]
}
//}
}
}
Function Query:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendFollowingNotifications = functions.database.ref('/users/{userId}/following/{followingId}')
//.onWrite(event => {
.onCreate((snap,context) => {
console.info("Child value is val() " ,snap);
var childNodeValue=snap.val();
var topic=childNodeValue.userId;
//var ref = firebase.database().ref.child('users');
//console.log("testing ref pathName : " ,snap.ref.parent.parent.parent.pathname);
// console.log("testing ref : " ,snap.ref.parent.parent.parent.path);
//var ref = admin.database().ref("users");
//.child('users')
return snap.ref.parent.parent.parent.orderByChild("userId").equalTo(childNodeValue.currentFollowingUserId)
// .on('child_changed').then(snapshot => { once('value')
.once('value', function(snapshot){
var parentNodeValue=snapshot.val();
console.info("Topic ID " ,topic);
console.info("Parent value is val() " ,snapshot.val());
var payload = {
data: {
username: parentNodeValue.userName,
imageurl:parentNodeValue.userProfileImage,
description:"Started Following You"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToTopic(topic, payload)
.then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return response;
})
.catch(function (error) {
console.log("Error sending message:", error);
return error;
});
});
});
return
snap.ref.parent.child('users').orderByChild("userId").equalTo(childNodeValue.currentFollowingUserId)
I think the problem is with this query , My first query on following node is returning me data but when I'm retrieving data of its parent node user, I'm getting warning.
I tried to use functions.database.ref but it gave me below exception.
so I tried using this `snap.ref.parent.`to get reference of parent node.
Firebase Functions, admin.database().ref(…) is not a function
Firebase Functions, functions.database().ref(…) is not a function
You are getting the wrong reference for reading the user. You need to do the following to get correct reference: snap.ref.parent.parent.parent (ref now will be at /users). You query is trying to read the users node under following.
The warning is that you need to write the firebase rule which enables the indexing based on userId, otherwise the operation will be bandwidth expensive.
here is the rule which will add indexing:
"users": {
"$uid" : {
".indexOn" : ["userId"]
}
}
Here is the resource for more information on Database rules : https://firebase.google.com/docs/database/security/
This is a simple tool by firebase to write rules easily: https://github.com/firebase/bolt
P.S: you are returning two promises your last promise for sending notification will not work. Nest or chain it with the firebase query. Also make your query single value event with changing on('child_changed') to once('value').

How do I access JSON data from a JSON file I receive via HTTP request in node.js?

var http = require('http');
var optionsget = {
host : 'demo4712411.mockable.io',
port : 80,
path : '/Jobs',
method : 'GET'
};
console.info('Options prepared:');
console.info(optionsget);
console.info('Do the GET call');
var reqGet = http.get(optionsget, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
console.log("------- ID " + res.Lat);
var buffer='';
res.on('data', function(d) {
console.log(d);
buffer += d.toString();
});
res.on('end', function() {
console.info('GET result:\n');
console.log(buffer);
console.info('\n\nCall completed');
});
});
reqGet.on('error', function(e) {
console.error("Error: --" + e);
});
reqGet.end();
So I am getting all the output I need, and I do get the JSON file as a string --
GET result:
{
"Id" : 23
"OwnerrId" : 233
"ProviderId" : 2343
"Lat" : 342.23423
"Long" : 23.32233
"Address" : "234 Maybach way, Bellevue 98803"
}
However, I am having trouble accessing the components of the JSON File (like Id, and OwnerrId). I have tried a couple things like JSON.parse(d), but that gives me an error. Not sure what to do.
It gives you an error because it isn't JSON. The commas between each key: value pair are missing.
Either fix the server you are requesting the data from so it returns real JSON or write a custom parser for the non-standard format.

JSON file not loading properly [duplicate]

This question already has answers here:
Get JSON data from external URL and display it in a div as plain text
(7 answers)
How to get the response of XMLHttpRequest?
(4 answers)
Closed 7 years ago.
I want to read this JSON file, but the xmlhttp is returning empty.
This is the getJson() function that I am using. I am running this from my local machine.
var getJSON = function(dir) {
console.log(dir);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
console.log(xmlhttp);
}
xmlhttp.open("GET", dir, true);
xmlhttp.send();
};
Alberto,
Since you are using xmlHttp asynchronously, and assuming you want to save the response in a variable, you'll have to modify your getJSON function to accept a callback function and pass the result and/or an error to the callback. So getJSON should be something like this:
var getJSON = function(dir, callback) {
console.log(dir);
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
if (xmlhttp.status == 200) {
console.log('request finished', xmlhttp);
// pass the response to the callback function
callback(null, xmlhttp.responseText);
} else {
// pass the error to the callback function
callback(xmlhttp.statusText);
}
}
}
xmlhttp.open("GET", dir, true);
xmlhttp.send();
}
To use the function, you'll want something like this:
var myReturnedJSON;
getJSON("http://gomashup.com/json.php?fds=geo/usa/zipcode/state/AL&jsoncallback=", function(error, data){
if(error) {
//handle the error
} else {
//no error, parse the data
myReturnedJSON = JSON.parse(data)
}
});
Now, the issue with this is that the source returns invalid JSON:
({
"result":[
{
"Longitude" : "-086.466833",
"Zipcode" : "35004",
"ZipClass" : "STANDARD",
"County" : "SAINT CLAIR",
"City" : "MOODY",
"State" : "AL",
"Latitude" : "+33.603543"
}
]}
)
For this to be valid, it should look like:
{
"result":[
{
"Longitude" : "-086.466833",
"Zipcode" : "35004",
"ZipClass" : "STANDARD",
"County" : "SAINT CLAIR",
"City" : "MOODY",
"State" : "AL",
"Latitude" : "+33.603543"
}
]}
The difference is in that the valid JSON is not wrapped in parentheses.
So, let's modify the callback function to strip out the first and last characters of the response:
function(error, data){
if(error) {
//handle the error
} else {
//no error, parse the data
myReturnedJSON = JSON.parse( data.substr(1, data.length - 2) );
}
}
I hope that helps!
- Oscar

Promise function giving 'SyntaxError: Unexpected token }'

I'm attempting to deploy my code to Parse, and I keep getting an error stating:
Update failed with Could not load triggers. The error was Uncaught SyntaxError: Unexpected token } in main.js:454
Of the code below, line 454 that it refers to is this one:
}, function(err) {
Full code:
Parse.Cloud.define("MatchCenterTest", function(request, response) {
//defines which parse class to iterate through
var matchCenterItem = Parse.Object.extend("matchCenterItem");
var query = new Parse.Query(matchCenterItem);
var promises = [];
//setting the limit of items at 10 for now
query.limit(10);
query.find().then(function(results) {
for (i=0; i<results.length; i++) {
url = 'http://svcs.ebay.com/services/search/FindingService/v1';
//push function containing criteria for every matchCenterItem into promises array
promises.push(function() {
return Parse.Cloud.httpRequest({
url: url,
params: {
'OPERATION-NAME' : 'findItemsByKeywords',
'SERVICE-VERSION' : '1.12.0',
'SECURITY-APPNAME' : '*APP ID GOES HERE*',
'GLOBAL-ID' : 'EBAY-US',
'RESPONSE-DATA-FORMAT' : 'JSON',
'REST-PAYLOAD&sortOrder' : 'BestMatch',
'paginationInput.entriesPerPage' : '3',
'outputSelector=AspectHistogram&itemFilter(0).name=Condition&itemFilter(0).value(0)' : results[i].get('itemCondition'),
'itemFilter(1).name=MaxPrice&itemFilter(1).value' : results[i].get('maxPrice'),
'itemFilter(1).paramName=Currency&itemFilter(1).paramValue' : 'USD',
'itemFilter(2).name=MinPrice&itemFilter(2).value' : results[i].get('minPrice'),
'itemFilter(2).paramName=Currency&itemFilter(2).paramValue' : 'USD',
//'itemFilter(3).name=LocatedIn&itemFilter(3).Value' : request.params.itemLocation,
'itemFilter(3).name=ListingType&itemFilter(3).value' : 'FixedPrice',
'keywords' : results[i].get('searchTerm'),
}
});
});
}
Parse.Promise.when(promises).then(function(){
var ebayPingResults = [];
forEach(function(httpResponse) {
var httpResponse = JSON.parse(httpResponse.text);
ebayPingResults.push(httpResponse);
});
response.success(
console.log(ebayPingResults[0]); // So you can see what the response looks like for each httpRequest that was made
)
}, function(err) {
console.log('error!');
response.error('DAMN IT MAN');
});
});
});
As far as I know, that bracket belongs there. Why is this error occurring?
This piece of code looks terribly wrong:
response.success(
console.log(ebayPingResults[0]); // So you can see what the response looks like for each httpRequest that was made
)
seems like it must be
response.success(function(result) {
console.log(result);
});
In cloud code functions, the code must call either response.success() or response.error(). Each of these take an optional value that will be JSON encoded and returned to the calling code.
Your current code is calling console.log() in an entirely wrong place, and breaking the code.
Returning an anon function is also incorrect.
If you want to return the array of ping results, just use the following:
response.success(ebayPingResults);
If you want to log something, do it before your response.success() call:
console.log(ebayPingResults[0]);
response.success(ebayPingResults);

JSON parsing issues are giving me a 'Cannot read property of undefined' error.

I'm working on cloud code that pings eBay, returns JSON, parses it, and stores the top two categories into an array. The parameters sent to eBay are based on what a user types into itemSearch bar the iOS app. When I attempt to send a query like "iPhone", it gives this error:
TypeError: Cannot read property 'findItemsByKeywordsResponse' of undefined
at Object.Parse.Cloud.httpRequest.success (main.js:37:15)
at Object.<anonymous> (<anonymous>:565:19) (Code: 141, Version: 1.2.18)
Here is my objective-c code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.nextButton) return;
if (self.itemSearch.text.length > 0) {
[PFCloud callFunctionInBackground:#"eBayCategorySearch"
withParameters:#{#"item": self.itemSearch.text}
block:^(NSString *result, NSError *error) {
if (!error) {
NSLog(#"Successfully pinged eBay!");
}
}];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
The cloud code (main.js) running on Parse:
Parse.Cloud.define("eBayCategorySearch", function(request, response) {
url = 'http://svcs.ebay.com/services/search/FindingService/v1';
Parse.Cloud.httpRequest({
url: url,
params: {
'OPERATION-NAME' : 'findItemsByKeywords',
'SERVICE-VERSION' : '1.12.0',
'SECURITY-APPNAME' : '*APP ID GOES HERE*',
'GLOBAL-ID' : 'EBAY-US',
'RESPONSE-DATA-FORMAT' : 'JSON',
'itemFilter(0).name=ListingType' : 'itemFilter(0).value=FixedPrice',
'keywords' : request.params.item,
// your other params
},
success: function (httpResponse) {
var response = JSON.parse(httpResponse.text)
// count number of times each unique primaryCategory shows up (based on categoryId), return top two (done with a for loop?)
var userCategories = {};
var data = httpResponse.data
data.findItemsByKeywordsResponse.searchResult[0].item.forEach(function(item)
{
var id = item.primaryCategory[0].categoryId;
if (userCategories[id]) userCategories[id]++;
else userCategories[id] = 1;
});
var top2 = Object.keys(userCategories).sort(function(a, b)
{return userCategories[b]-userCategories[a]; }).slice(0, 2);
console.log('Top two categories: ' + top2.join(', '));
response.success(httpResponse.data)
// if user has criteria info for one of the categories already, default to that, send to matchcenter
// if user has criteria for both categories, ask which one, default to selected categories criteria, send to matchcenter
// if user has no criteria for either category, redirect to criteriaViewController, save the criteria user inputs, send to matchcenter
// deal with success and respond to query
},
error: function (httpResponse) {
console.log('error!!!');
console.error('Request failed with response code ' + httpResponse.status);
}
});
});
The JSON usually looks like this when returned:
{
"findItemsByKeywordsResponse":[
{
"ack":[
"Success"
],
"version":[
"1.12.0"
],
"timestamp":[
"2014-03-26T18:29:40.583Z"
],
"searchResult":[
{
"#count":"100",
"item":[
{
"itemId":[
"151258132867"
],
"title":[
"Apple iPhone 4 - clean esn - Black (Verizon) Smartphone"
],
"globalId":[
"EBAY-US"
],
"primaryCategory":[
{
"categoryId":[
"9355"
],
"categoryName":[
"Cell Phones & Smartphones"
I don't think it's being returned properly, hence its inability to find "findItemsByKeywordsResponse". Is there a way I can print out the JSON being returned, to see whether I'm parsing the wrong thing?
You are parsing your response:
var response = JSON.parse(httpResponse.text)
But after that you don't use it. You work instead with httpResponse.data.
So try using your response object:
response.findItemsByKeywordsResponse.searchResult[0]......

Categories

Resources