I'll try to provide as much information as I think might be relevant. I'm using NodeJS, MongoDB, .rest, and Render, though in this case I'm just trying to get things working locally first. Here are some of the files.
//swagger.js
const swaggerAutogen = require('swagger-autogen')();
const doc = {
info: {
title: 'My API',
description: 'Welcome to my fumbling mess',
},
host: 'localhost:3000',
schemes: ['http'],
};
const outputFile = './swagger-output.json';
const endpointsFiles = ['routes/index.js'];
swaggerAutogen(outputFile, endpointsFiles, doc);
//routes/index.js
const routes = require('express').Router();
routes.use('/characters', require('./characters'));
routes.use('/', require('./swagger-route'));
module.exports = routes;
//routes/swagger-route.js
const router = require('express').Router();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('../swagger-output.json');
router.use('/api-docs', swaggerUi.serve);
router.use('/api-docs', swaggerUi.setup(swaggerDocument));
module.exports = router;
//swagger.output.json
{
"swagger": "2.0",
"info": {
"title": "My API",
"description": "Welcome to my fumbling mess",
"version": "1.0.0"
},
"host": "localhost:3000",
"basePath": "/",
"schemes": [
"http"
],
"paths": {
"/characters/": {
"get": {
"description": "",
"produces": [
"application/json"
],
"parameters": [],
"responses": {
"200": {
"description": "OK"
},
"500": {
"description": "Internal Server Error"
}
}
},
"post": {
"description": "",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"type": "object",
"properties": {
"characterName": {
"example": "any"
},
"playerName": {
"example": "any"
},
"race": {
"example": "any"
},
"class": {
"example": "any"
},
"level": {
"example": "any"
},
"alignment": {
"example": "any"
},
"stats": {
"example": "any"
}
}
}
}
],
"responses": {
"201": {
"description": "Created"
},
"400": {
"description": "Bad Request"
}
}
}
},
"/characters/{id}": {
"get": {
"description": "",
"produces": [
"application/json"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
},
"500": {
"description": "Internal Server Error"
}
}
},
"put": {
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"schema": {
"type": "object",
"properties": {
"characterName": {
"example": "any"
},
"playerName": {
"example": "any"
},
"race": {
"example": "any"
},
"class": {
"example": "any"
},
"level": {
"example": "any"
},
"alignment": {
"example": "any"
},
"stats": {
"example": "any"
}
}
}
}
],
"responses": {
"204": {
"description": "No Content"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
}
}
},
"delete": {
"description": "",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
},
"404": {
"description": "Not Found"
},
"500": {
"description": "Internal Server Error"
}
}
}
}
}
}
And finally, running http://localhost:3000/api-docs/ doesn't result in the actual frontend of the Swagger UI like it should. Instead I get this is raw html in the attached image.
Any ideas of what I could be doing wrong?
I tried in swagger-route.js to change the 5th line from router.get() to router.use()
I tried forgetting about localhost and changing the host paths to my Render web service but that just caused the same thing to happen on Render.
I am using React/Typescript in my application but need help with basic JavaScript. I am trying to group the data coming from an api call (in this example i'll use mock data) without modifying the actual JSON. I need to group the data based on the 'deviceType' value. So if there are 4 objects, if two are ipad and two are iphone, I need to group those in order. Right now, the mock data is showing Ipad air, then Iphone 6plus, then Ipad air, and then Iphone 6plus again. I need to group these so the new object has the two ipadAir objects first and then the iphone 6plus object coming after. I believe this can be done by making a copy of the old object using spread operator and then modifying it before returning. Here is the data object:
{
"data": {
"DirectvNowDeviceNotifications": [
{
"AccountNumber": "180802190357553",
"AlertDescription": [
{
"AlertType": "BUFFERINGERRORS",
"AlertCode": "CRITICAL_ISFATAL",
"AlertInfo": "ACCOUNT_ALERT",
"SkipDismissal": false,
"DISMISSAL_EXPIRY_DATE": "",
"Content": {
"issueTitle": "Buffering Error Detected",
"issueDescription": "Buffering Error Detected"
},
"AlertAdditionalInfo": [
{
"Name": "reasonCodes",
"Value": "CRITICAL_ISFATAL"
},
{
"Name": "make",
"Value": "APPLE"
},
{
"Name": "deviceType",
"Value": "IPAD AIR"
},
{
"Name": "deviceID",
"Value": "F920BE29-1321-498A-B5D7-7FA84396DE16"
},
{
"Name": "osName",
"Value": "IOS"
},
{
"Name": "ISP",
"Value": "TIME WARNER CABLE INTERNET LLC"
},
{
"Name": "Mobile Carrier",
"Value": "AT&T"
},
{
"Name":"workflowName",
"Value":"CCE_ATTTV_Wifi_Setup"
}
],
"AdditionalContent": {
"longDescription": "You received this error message because the system has captured buffering errors on your device while streaming."
}
},
{
"AlertType": "BUFFERINGERRORS",
"AlertCode": "CRITICAL_FATALV",
"AlertInfo": "ACCOUNT_ALERT",
"SkipDismissal": false,
"DISMISSAL_EXPIRY_DATE": "",
"Content": {
"issueTitle": "Buffering Error Detected",
"issueDescription": "Buffering Error Detected"
},
"AlertAdditionalInfo": [
{
"Name": "reasonCodes",
"Value": "CRITICAL_FATALVIDEOERROR_CT"
},
{
"Name": "make",
"Value": "APPLE"
},
{
"Name": "deviceType",
"Value": "IPHONE 6 PLUS"
},
{
"Name": "deviceID",
"Value": "F920BE29-1321-498A-B5D7-7FA84396DE16"
},
{
"Name": "osName",
"Value": "IOS"
},
{
"Name": "ISP",
"Value": "TIME WARNER CABLE INTERNET LLC"
},
{
"Name": "Mobile Carrier",
"Value": "AT&T"
},
{
"Name":"workflowName",
"Value":"CCE_DTVN_PLAYER_ERRORS"
},
{
"Name":"workflowName",
"Value":"CCE_DTVN_PLAYER_ERRORS"
}
],
"AdditionalContent": {
"longDescription": "You received this error message because the system has captured buffering errors on your device while streaming"
}
},
{
"AlertType": "OSUNSUPPORTED",
"AlertCode": "N_NOT_SUPPORTED",
"AlertInfo": "ACCOUNT_ALERT",
"SkipDismissal": false,
"DISMISSAL_EXPIRY_DATE": "",
"Content": {
"issueTitle": "The device you are trying to use with DIRECTV NOW is not supported.",
"issueDescription": "The device you are trying to use with DIRECTV NOW is not supported."
},
"AlertAdditionalInfo": [
{
"Name": "reasonCodes",
"Value": "VSTB_UNSUPPORTED_DEVICE"
},
{
"Name": "make",
"Value": "APPLE"
},
{
"Name": "deviceType",
"Value": "IPAD AIR"
},
{
"Name": "deviceID",
"Value": "F920BE29-1321-498A-B5D7-7FA84396DE16"
},
{
"Name": "osName",
"Value": "IOS"
},
{
"Name": "ISP",
"Value": "TIME WARNER CABLE INTERNET LLC"
},
{
"Name": "Mobile Carrier",
"Value": "AT&T"
},
{
"Name":"workflowName",
"Value":"CCE_DTVN_PLAYER_ERRORS"
}
],
"AdditionalContent": {
"longDescription": "<a target='_blank' href='https://www.att.com/esupport/article.html#!/directv-now/KM1200941'>Here</a> is a list of supported devices."
}
},
{
"AlertType": "NA",
"AlertCode": "NA",
"AlertInfo": "NA",
"SkipDismissal": false,
"DISMISSAL_EXPIRY_DATE": "",
"Content": {
"issueTitle": "tell me more title",
"issueDescription": "tell me more description"
},
"AlertAdditionalInfo": [
{
"Name": "reasonCodes",
"Value": "NA"
},
{
"Name": "make",
"Value": "APPLE"
},
{
"Name": "deviceType",
"Value": "IPHONE 6 PLUS"
},
{
"Name": "deviceID",
"Value": "FB2468CF-BF73-4DBC-9600-C61553BB759F"
},
{
"Name": "osName",
"Value": "IOS"
},
{
"Name": "ISP",
"Value": "TIME WARNER CABLE INTERNET LLC"
},
{
"Name": "Mobile Carrier",
"Value": "AT&T"
}
],
"AdditionalContent": {
"longDescription": "tell me more long long long description"
}
}
]
}
]
},
"content": {
"code": 200,
"message": "OK"
}
}
Need objects to be grouped based on device type and return a new object with the proper grouping. Please if anyone can help I would greatly appreciate it, I have been struggling with this. Thank you
You could go through the keys of your object, in the following example I assume that you define this as a javascript object, the result will be two objects each with a key corresponding to the type of device
const newGroup = [];
const data = object["data"]["DirectvNowDeviceNotifications"];
(data).forEach((map, index) => {
Object(map['AlertDescription']).forEach((devices) => {
if(typeof devices['AlertAdditionalInfo'] !== 'undefined'){
const deviceType = devices['AlertAdditionalInfo'].find((type) => type.Name ==='deviceType');
if(typeof deviceType.Value !== 'undefined'){
if(typeof newGroup[deviceType.Value] === 'undefined'){
newGroup[deviceType.Value] = [];
}
newGroup[deviceType.Value].push(devices);
}
}
})
});
example working
this code is just an example you should optimize, the idea is to give you an idea of solution
So I have a bunch of JSON data and it contains a few fields. for example:
[{
"id": "XXX",
"version": 1,
"head": {
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
},
"body": [{
"id": "XXX1",
"info": "three little birds",
"extended": {
"spl": {
"text": "song",
"type": {
"value": "a"
}
}
}
},
{
"id": "XXX2",
"info": [
"how are you?"
],
"extended": {
"spl": {
"text": "just",
"non-type": {
"value": "abc"
}
}
}
}
]
}]
what I'm trying to do is kind of conversion table (from a different JSON file)
if a field has the value 'a' replace it with 'some other text..' etc.
I have a service for the JSON pipeline, so I guess this is the right place to do the replacement.
so for this example, I have the JSON above and in my conversion table I have the following terms:
next: forward,
song: music,
a: option1,
just: from
etc...
What you are looking for can be achieved with templates. Replace the variable sections with some specific markers that you can find and replace from some external tools such as perl or sed.
For example, you could have a template.json with something like this:
...
"type": {
"value": "##VALUE##"
}
...
Then when you need the actual JSON, you could pass this though an intermediate script that replaces these templates with actual data.
cat template.json | sed -e 's/##VALUE##/my_value/' > target.json
Alternatively, with Perl:
cat template.json | perl -pi -e 's:\#\#VALUE\#\#:my_value:' > target.json
The best way is to parse it, replace the text in the object, and then stringify it.
The next best way is to use a regular expression.
In this example, I catch exceptions if path cannot be indexed, and use ['type'] instead of .type so it will scale to indexing 'non-type' if you wish.
const data = `[{
"id": "XXX",
"version": 1,
"head": {
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
},
"body": [{
"id": "XXX1",
"info": "three little birds",
"extended": {
"spl": {
"text": "song",
"type": {
"value": "a"
}
}
}
},
{
"id": "XXX2",
"info": [
"how are you?"
],
"extended": {
"spl": {
"text": "just",
"non-type": {
"value": "abc"
}
}
}
}
]
}]
`
const o = JSON.parse(data)
o[0].body.forEach(b => {
try {
if (b.extended.spl['type'].value === 'a') {
b.extended.spl['type'].value = 'CHANGED'
}
} catch (e) {}
})
const newData = JSON.stringify(o, null, 2)
console.log(newData)
A string replace approach will work if you know and can rely on your source conforming, such as the only "value" is inside "type"
const data = `[{
"id": "XXX",
"version": 1,
"head": {
"text": "Main title",
"sub": {
"value": "next"
},
"place": "secondary"
},
"body": [{
"id": "XXX1",
"info": "three little birds",
"extended": {
"spl": {
"text": "song",
"type": {
"value": "a"
}
}
}
},
{
"id": "XXX2",
"info": [
"how are you?"
],
"extended": {
"spl": {
"text": "just",
"non-type": {
"value": "abc"
}
}
}
}
]
}]
`
const newData = data.replace(/"value": "a"/g, '"value": "NEWVALUE"')
console.log(newData)
I'm new to Actions on Google and Node.js, but this seems like it should be straightforward and I'm not sure why it's not working. I just want to send a GET request within the code that handles a specific intent. At the moment, I'm not even looking for a return value; I just want to fire off the request. I'm using the Blaze tier of Firebase, which is supposed to allow outgoing HTTPS requests. Indeed, I can get the Action to play an audio file from my server in SSML. But when I put in a GET request to a PHP page that increments a value in a database, it isn't being executed successfully.
My code is taken directly from Google's CodeLabs tutorials for Actions. Below is the only function I'm modifying. This code runs, but the GET request is never received.
// Handle the Dialogflow intent named 'favorite color'.
// The intent collects a parameter named 'color'.
app.intent('favorite color', (conv, {color}) => {
const luckyNumber = color.length;
const audioSound = 'https://my.server.tld/path/to/sound.mp3';
// These two lines don't seem to do what I'm expecting them to.
var https = require("https");
https.get('https://my.server.tld/path/to/file.php?value=1');
conv.ask(`<speak>Your lucky number is ${luckyNumber}.` +
`<audio src="${audioSound}"></audio>` +
`Would you like to hear some fake colors?</speak>`);
});
There's nothing that jumps out at me as unusual in the Firebase logs (excerpted below). There doesn't seem to be any mention of the GET call I'm trying to make.
4:19:11.631 PM dialogflowFirebaseFulfillment Function execution took 569 ms, finished with status code: 200
4:19:11.543 PM dialogflowFirebaseFulfillment Response { "status": 200, "headers": { "content-type": "application/json; charset=utf-8" }, "body": { "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "<speak>Three. Your lucky number is 4.<audio src=\"https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg\"></audio>Would you like to hear some fake colors?</speak>" } } ] }, "userStorage": "{\"data\":{}}" } }, "outputContexts": [ { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/_actions_on_google", "lifespanCount": 99, "parameters": { "data": "{}" } } ] } }
4:19:11.434 PM dialogflowFirebaseFulfillment Conversation { "responses": [], "expectUserResponse": true, "digested": false, "noInputs": [], "_responded": false, "request": "[Excluded]", "headers": "[Excluded]", "sandbox": true, "input": { "raw": "blue", "type": "KEYBOARD" }, "surface": { "capabilities": { "list": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } }, "available": { "surfaces": { "list": [ { "capabilities": { "list": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } } ], "capabilities": { "surfaces": [ { "capabilities": { "list": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } } ] } } }, "user": { "raw": { "userStorage": "{\"data\":{}}", "lastSeen": "2018-09-26T23:19:06Z", "locale": "en-US", "userId": "ABwppHHp5yhn_VrB_SIGG93tCzMx9o0A_W9bIDlbCClkqcV85LrVbJ42vLQ7hWXfe3UOd7pASDIm6v_q" }, "storage": {}, "_id": "ABwppHHp5yhn_VrB_SIGG93tCzMx9o0A_W9bIDlbCClkqcV85LrVbJ42vLQ7hWXfe3UOd7pASDIm6v_q", "locale": "en-US", "permissions": [], "last": { "seen": "2018-09-26T23:19:06.000Z" }, "name": {}, "entitlements": [], "access": {}, "profile": {} }, "arguments": { "parsed": { "input": { "text": "blue" }, "list": [ "blue" ] }, "status": { "input": {}, "list": [ null ] }, "raw": { "list": [ { "rawText": "blue", "textValue": "blue", "name": "text" } ], "input": { "text": { "rawText": "blue", "textValue": "blue", "name": "text" } } } }, "device": {}, "id": "ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh", "type": "ACTIVE", "screen": true, "body": "[Excluded]", "version": 2, "action": "", "intent": "favorite color", "parameters": { "color": "blue" }, "contexts": { "_session": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh", "input": { "actions_capability_screen_output": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_screen_output", "parameters": { "color": "blue", "color.original": "blue" } }, "actions_capability_audio_output": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_audio_output", "parameters": { "color": "blue", "color.original": "blue" } }, "google_assistant_input_type_keyboard": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/google_assistant_input_type_keyboard", "parameters": { "color": "blue", "color.original": "blue" } }, "actions_capability_web_browser": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_web_browser", "parameters": { "color": "blue", "color.original": "blue" } }, "actions_capability_media_response_audio": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_media_response_audio", "parameters": { "color": "blue", "color.original": "blue" } } }, "output": {} }, "incoming": { "parsed": [ "" ] }, "query": "blue", "data": {} }
4:19:11.346 PM dialogflowFirebaseFulfillment Headers { "host": "us-central1-actions-rwag.cloudfunctions.net", "user-agent": "Apache-HttpClient/4.5.4 (Java/1.8.0_181)", "transfer-encoding": "chunked", "accept": "text/plain, */*", "accept-charset": "big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-compound_text, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp", "content-type": "application/json; charset=UTF-8", "function-execution-id": "gjnwrdpyi1ax", "x-appengine-api-ticket": "e212b331d87bdb3c", "x-appengine-city": "?", "x-appengine-citylatlong": "0.000000,0.000000", "x-appengine-country": "US", "x-appengine-default-version-hostname": "l9ec7ba250478215b-tp.appspot.com", "x-appengine-https": "on", "x-appengine-region": "?", "x-appengine-request-log-id": "5bac13ef00ff00ffe3280c8cb3550001737e6c396563376261323530343738323135622d7470000139303866373866633530636138623435363966303164656633393333393136383a3233000100", "x-appengine-user-ip": "35.239.85.110", "x-cloud-trace-context": "0109e1b3b7dc8fbbefd2664dbcbd5d0a/2770932151653705781;o=1", "x-forwarded-for": "35.239.85.110, 35.239.85.110", "x-forwarded-proto": "https", "accept-encoding": "gzip" }
4:19:11.339 PM dialogflowFirebaseFulfillment Request { "responseId": "c7b55f8a-502d-431a-8056-258dec82268f", "queryResult": { "queryText": "blue", "parameters": { "color": "blue" }, "allRequiredParamsPresent": true, "fulfillmentMessages": [ { "text": { "text": [ "" ] } } ], "outputContexts": [ { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_screen_output", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_audio_output", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/google_assistant_input_type_keyboard", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_web_browser", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_media_response_audio", "parameters": { "color": "blue", "color.original": "blue" } } ], "intent": { "name": "projects/actions-rwag/agent/intents/8524ede6-72a2-467b-9b34-67a8f1d3a121", "displayName": "favorite color" }, "intentDetectionConfidence": 1, "languageCode": "en-us" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "isInSandbox": true, "surface": { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] }, "requestType": "SIMULATOR", "inputs": [ { "rawInputs": [ { "query": "blue", "inputType": "KEYBOARD" } ], "arguments": [ { "rawText": "blue", "textValue": "blue", "name": "text" } ], "intent": "actions.intent.TEXT" } ], "user": { "userStorage": "{\"data\":{}}", "lastSeen": "2018-09-26T23:19:06Z", "locale": "en-US", "userId": "ABwppHHp5yhn_VrB_SIGG93tCzMx9o0A_W9bIDlbCClkqcV85LrVbJ42vLQ7hWXfe3UOd7pASDIm6v_q" }, "conversation": { "conversationId": "ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh", "type": "ACTIVE", "conversationToken": "[]" }, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } ] } }, "session": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh" }
4:19:11.063 PM dialogflowFirebaseFulfillment Function execution started
I think I've discovered why I was running into this problem, and why I couldn't explain it based on research into Actions on Google or Node.js. It looks like the page on my server that I was requesting returns a 301 "Permanently Moved" response. When I request the page through a web browser, it ignores(?) this response and serves the page anyway, but when I make the request in my AoG intent fulfillment, it silently recognizes the 301 and doesn't ever hit the PHP on the server. Anyway, it appears this is a problem with my server configuration and not my AoG code.
Hot tip to new AoG programmers: console.log() commands in the fulfillment will appear in the Firebase Cloud Functions log, which is what eventually allowed me to see the 301 code being returned. Thanks to anyone how tried to puzzle this out with me!
I have a nested JSON returned from an API that I am hitting using a GET request, in POSTMAN chrome app. My JSON looks like this
"result": [
{
"_id": "some_id",
"name": "India",
"code": "IN",
"link": "http://www.india.info/",
"closingTime": "2017-02-25T01:12:17.860Z",
"openingTime": "2017-02-25T06:12:17.205Z",
"image": "image_link",
"status": "online",
"serverStatus": "online",
"games": [
{
"_id": "some_game_id1",
"name": "Cricket"
},
{
"_id": "some_another_id1",
"name": "Baseball"
},
{
"_id": "some_another_id_2",
"name": "Basketball"
}
]
},
{
"_id": "some_id",
"name": "Australia",
"code": "AUS",
"link": "https://www.lonelyplanet.com/aus/adelaide",
"closingTime": "2017-02-28T05:13:38.022Z",
"openingTime": "2017-02-28T05:13:38.682Z",
"image": "some_image_url",
"status": "offline",
"serverStatus": "online",
"games": [
{
"_id": "some_game_id_2",
"name": "Cricket"
},
{
"_id": "some_another_id_3",
"name": "Kho-Kho"
},
{
"_id": "some_another_id_4",
"name": "Badminton"
},
{
"_id": "some_another_id_5",
"name": "Tennis"
}
]
},
I am trying to test whether my response body has "name":"India" and the "game" with "some_game_id1" contains the "name":"cricket".
I went through this link where the answer is to have an array for "name"created and then check within the array whether the array contains the value. I tried this but my code fails.
Also, I tried searching the element by the index within the JSON body using this -
var searchJSON = JSON.parse(responseBody);
tests["name contains India"] = searchJSON.result.name[0]==="India";
But this also fails. I tried using the .value appended with the second line of above code, but it also fails. How can I check this thing?
You need to put [0] after result (which is an array) rather than name (which is a string).
Also, use a regular expression to check whether the name contains 'India', because using === only checks if the name is exactly India.
var searchJSON = JSON.parse(responseBody)
tests["name contains India"] = /India/.test(searchJSON.result[0].name)
Demo Snippet:
var responseBody = `{
"result": [{
"_id": "some_id",
"name": "India",
"code": "IN",
"link": "http://www.india.info/",
"closingTime": "2017-02-25T01:12:17.860Z",
"openingTime": "2017-02-25T06:12:17.205Z",
"image": "image_link",
"status": "online",
"serverStatus": "online",
"games": [{
"_id": "some_game_id1",
"name": "Cricket"
},
{
"_id": "some_another_id1",
"name": "Baseball"
},
{
"_id": "some_another_id_2",
"name": "Basketball"
}
]
},
{
"_id": "some_id",
"name": "Australia",
"code": "AUS",
"link": "https://www.lonelyplanet.com/aus/adelaide",
"closingTime": "2017-02-28T05:13:38.022Z",
"openingTime": "2017-02-28T05:13:38.682Z",
"image": "some_image_url",
"status": "offline",
"serverStatus": "online",
"games": [{
"_id": "some_game_id_2",
"name": "Cricket"
},
{
"_id": "some_another_id_3",
"name": "Kho-Kho"
},
{
"_id": "some_another_id_4",
"name": "Badminton"
},
{
"_id": "some_another_id_5",
"name": "Tennis"
}
]
}
]
}`
var tests = {}
var searchJSON = JSON.parse(responseBody)
tests["name contains India"] = /India/.test(searchJSON.result[0].name)
console.log(tests) //=> { "name contains India": true }