How to host Alexa Skill using Express API (Web Server) - alexa-skills-kit

I've been stuck with hosting an alexa skill webserver on my localhost!
Everything's correct from the Intents I've made, the url works, and it does request the intent I ask it for, but Alexa constantly keeps saying "There was a problem with the requested skill's response"
const express = require("express");
const Alexa = require('ask-sdk-core');
const { ExpressAdapter } = require("ask-sdk-express-adapter");
const app = express();
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Hello World - Your skill has launched';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Hello World', speechText)
.getResponse();
}
};
const builder = Alexa.SkillBuilders.custom();
builder.addRequestHandlers(
LaunchRequestHandler
);
const skill = builder.create();
const adapter = new ExpressAdapter(skill, false, false);
app.post('/', adapter.getRequestHandlers());
app.listen(443, null, () => {
console.log("App is now online!");
});
This is the json body it gives when it tries to send a post / first
{
"version": "1.0",
"session": {
"new": false,
"sessionId": "amzn1.echo-api.session.325e7e93-3033-4e26-ada6-45f7967971bf",
"application": {
"applicationId": "amzn1.ask.skill.c1ed78ba-9003-4904-9376-b9a05b3a4bcc"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.AH7FLOU7DBFRWVIENTV7VT7EMQLPAGYMFU4YUTI6OSBCK6GOKXWNQ6BI3BPZPEMN2TQFXGZCO43KXB3HJNVJPBJILPEDLGIAMQK2DK3C42S5FBPCQSN6B46FMQDATFSCL42YCF25PR5CFPGHYUFIDIJHZAJRIGMZ5BGZMU7FNJB4I6KBVDF5N2WIXCIG6YMV2X4ZO3QETGA23HQ"
}
},
"context": {
"Viewports": [
{
"type": "APL",
"id": "main",
"shape": "RECTANGLE",
"dpi": 213,
"presentationType": "STANDARD",
"canRotate": false,
"configuration": {
"current": {
"mode": "HUB",
"video": {
"codecs": [
"H_264_42",
"H_264_41"
]
},
"size": {
"type": "DISCRETE",
"pixelWidth": 1280,
"pixelHeight": 800
}
}
}
}
],
"Viewport": {
"experiences": [
{
"arcMinuteWidth": 346,
"arcMinuteHeight": 216,
"canRotate": false,
"canResize": false
}
],
"mode": "HUB",
"shape": "RECTANGLE",
"pixelWidth": 1280,
"pixelHeight": 800,
"dpi": 213,
"currentPixelWidth": 1280,
"currentPixelHeight": 800,
"touch": [
"SINGLE"
],
"video": {
"codecs": [
"H_264_42",
"H_264_41"
]
}
},
"Extensions": {
"available": {
"aplext:backstack:10": {}
}
},
"System": {
"application": {
"applicationId": "amzn1.ask.skill.c1ed78ba-9003-4904-9376-b9a05b3a4bcc"
},
"user": {
"userId": "amzn1.ask.account.AH7FLOU7DBFRWVIENTV7VT7EMQLPAGYMFU4YUTI6OSBCK6GOKXWNQ6BI3BPZPEMN2TQFXGZCO43KXB3HJNVJPBJILPEDLGIAMQK2DK3C42S5FBPCQSN6B46FMQDATFSCL42YCF25PR5CFPGHYUFIDIJHZAJRIGMZ5BGZMU7FNJB4I6KBVDF5N2WIXCIG6YMV2X4ZO3QETGA23HQ"
},
"device": {
"deviceId": "amzn1.ask.device.AGZ65ZMWRSISWS4RB63ZEBKJDJPMICI5WU6SDYTU7CZKDFASRAAR7WNYRTVKYWRURCC77E2EIGXBBUTO3REKDGWMLJDN7ODAHKWJLJCTNHN3CU3LVXDMGRJJ3HIXMWRLVT6D5OFWNYXZ73J7Y6TCONRXYL2OTJHRQ7SUGQKEBBIPNVIYZ35WI",
"supportedInterfaces": {}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLmMxZWQ3OGJhLTkwMDMtNDkwNC05Mzc2LWI5YTA1YjNhNGJjYyIsImV4cCI6MTYzODQ5ODQ3OCwiaWF0IjoxNjM4NDk4MTc4LCJuYmYiOjE2Mzg0OTgxNzgsInByaXZhdGVDbGFpbXMiOnsiY29udGV4dCI6IkFBQUFBQUFBQUFCR0RiSjZDeWU5dHdCWmpETE5uQm0xS2dFQUFBQUFBQUNURkVXSEtNMGpPaWJXeUxvaWtmM2l3MkNBdGRDMThURG5vNWgvVEI1SkdnR3htRU95cHBhWGg1WWpORVZnMzZ6OVNNR0hCeVNZVmw4QnNVVmRzT0ZUVjV1QVdIdVdSeXp5a0dZaGhOTDdpbXdFaE9xR1hxaFBaMUhjbjJkYXhmNW5WaE44dkRuWGZqdVhTMkNJdFVxZjNHMXZhYkxwMVdRSDV1Q1d3QVFzWUxkSSt6d21RMVpNWk13Q25yZy9Bd3QxOWNQQjVCTDYwSGRVODI1MlBDa2Fna3EybzQ5eUxaM0d2R2NIZkNobzhnVlBMU0l1VGhndW1UWGtUY2Fsd0ZvMUthTEV2QS9VK1hDUW01MUg1TThxM1Eyc04zR1ZKSWpUV25yWDQrdG15a2wxOGo1dWRtT0loZjUwNlVEY1lYWDZqaW5KNzltYWptaHphVmpZcmNlOUpQSXgwMU5wZ2l1Z05FR092N3RxdHVsZjlvUHI4bmJxSWJZR1dacmdEMzdGcHUvd1FQVm9hZjExIiwiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUdaNjVaTVdSU0lTV1M0UkI2M1pFQktKREpQTUlDSTVXVTZTRFlUVTdDWktERkFTUkFBUjdXTllSVFZLWVdSVVJDQzc3RTJFSUdYQkJVVE8zUkVLREdXTUxKRE43T0RBSEtXSkxKQ1ROSE4zQ1UzTFZYRE1HUkpKM0hJWE1XUkxWVDZENU9GV05ZWFo3M0o3WTZUQ09OUlhZTDJPVEpIUlE3U1VHUUtFQkJJUE5WSVlaMzVXSSIsInVzZXJJZCI6ImFtem4xLmFzay5hY2NvdW50LkFIN0ZMT1U3REJGUldWSUVOVFY3VlQ3RU1RTFBBR1lNRlU0WVVUSTZPU0JDSzZHT0tYV05RNkJJM0JQWlBFTU4yVFFGWEdaQ080M0tYQjNISk5WSlBCSklMUEVETEdJQU1RSzJESzNDNDJTNUZCUENRU042QjQ2Rk1RREFURlNDTDQyWUNGMjVQUjVDRlBHSFlVRklESUpIWkFKUklHTVo1QkdaTVU3Rk5KQjRJNktCVkRGNU4yV0lYQ0lHNllNVjJYNFpPM1FFVEdBMjNIUSJ9fQ.X2fY3XTWW8zRZtwE6km2AIaSnhaAfSLKYqzgwlZrui6OyCS03Lfh1dJWHg4sZxTZqWyssV7VFWErW-gTZFUdkagtbbknuZQ3qlVQlwpZPaKhKBYC9VBDfmnGtjjDDCAAUyvB8ZIInbuxsrZ6DwYtuj5sa5_wGSfc0s2THQqP9Azklgk5UobwMN0iWsrhDSXy4guB4KaEJscD8_OLr2ZnbvWqy3tAPv3zfEsb8OmnOC7FBMHHgN-aCIRubnZNu8YA2Xtf-usOn1wVAjaIwEdlfgrOCRfFpZc3l7tfHTfX9HfLerRFh_IWQWc61DVfQZhyH4yeH5fdKUVDMels4zXlKQ"
}
},
"request": {
"type": "SessionEndedRequest",
"requestId": "amzn1.echo-api.request.e6d2bca6-4680-4367-8bb1-104e038c35ba",
"timestamp": "2021-12-03T02:22:58Z",
"locale": "en-US",
"reason": "ERROR",
"error": {
"type": "INVALID_RESPONSE",
"message": "An exception occurred while dispatching the request to the skill."
}
}
}
And the 2nd json body post / request when it errors:
{
"version": "1.0",
"session": {
"new": false,
"sessionId": "amzn1.echo-api.session.325e7e93-3033-4e26-ada6-45f7967971bf",
"application": {
"applicationId": "amzn1.ask.skill.c1ed78ba-9003-4904-9376-b9a05b3a4bcc"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.AH7FLOU7DBFRWVIENTV7VT7EMQLPAGYMFU4YUTI6OSBCK6GOKXWNQ6BI3BPZPEMN2TQFXGZCO43KXB3HJNVJPBJILPEDLGIAMQK2DK3C42S5FBPCQSN6B46FMQDATFSCL42YCF25PR5CFPGHYUFIDIJHZAJRIGMZ5BGZMU7FNJB4I6KBVDF5N2WIXCIG6YMV2X4ZO3QETGA23HQ"
}
},
"context": {
"Viewports": [
{
"type": "APL",
"id": "main",
"shape": "RECTANGLE",
"dpi": 213,
"presentationType": "STANDARD",
"canRotate": false,
"configuration": {
"current": {
"mode": "HUB",
"video": {
"codecs": [
"H_264_42",
"H_264_41"
]
},
"size": {
"type": "DISCRETE",
"pixelWidth": 1280,
"pixelHeight": 800
}
}
}
}
],
"Viewport": {
"experiences": [
{
"arcMinuteWidth": 346,
"arcMinuteHeight": 216,
"canRotate": false,
"canResize": false
}
],
"mode": "HUB",
"shape": "RECTANGLE",
"pixelWidth": 1280,
"pixelHeight": 800,
"dpi": 213,
"currentPixelWidth": 1280,
"currentPixelHeight": 800,
"touch": [
"SINGLE"
],
"video": {
"codecs": [
"H_264_42",
"H_264_41"
]
}
},
"Extensions": {
"available": {
"aplext:backstack:10": {}
}
},
"System": {
"application": {
"applicationId": "amzn1.ask.skill.c1ed78ba-9003-4904-9376-b9a05b3a4bcc"
},
"user": {
"userId": "amzn1.ask.account.AH7FLOU7DBFRWVIENTV7VT7EMQLPAGYMFU4YUTI6OSBCK6GOKXWNQ6BI3BPZPEMN2TQFXGZCO43KXB3HJNVJPBJILPEDLGIAMQK2DK3C42S5FBPCQSN6B46FMQDATFSCL42YCF25PR5CFPGHYUFIDIJHZAJRIGMZ5BGZMU7FNJB4I6KBVDF5N2WIXCIG6YMV2X4ZO3QETGA23HQ"
},
"device": {
"deviceId": "amzn1.ask.device.AGZ65ZMWRSISWS4RB63ZEBKJDJPMICI5WU6SDYTU7CZKDFASRAAR7WNYRTVKYWRURCC77E2EIGXBBUTO3REKDGWMLJDN7ODAHKWJLJCTNHN3CU3LVXDMGRJJ3HIXMWRLVT6D5OFWNYXZ73J7Y6TCONRXYL2OTJHRQ7SUGQKEBBIPNVIYZ35WI",
"supportedInterfaces": {}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLmMxZWQ3OGJhLTkwMDMtNDkwNC05Mzc2LWI5YTA1YjNhNGJjYyIsImV4cCI6MTYzODQ5ODQ3OCwiaWF0IjoxNjM4NDk4MTc4LCJuYmYiOjE2Mzg0OTgxNzgsInByaXZhdGVDbGFpbXMiOnsiY29udGV4dCI6IkFBQUFBQUFBQUFCR0RiSjZDeWU5dHdCWmpETE5uQm0xS2dFQUFBQUFBQUNURkVXSEtNMGpPaWJXeUxvaWtmM2l3MkNBdGRDMThURG5vNWgvVEI1SkdnR3htRU95cHBhWGg1WWpORVZnMzZ6OVNNR0hCeVNZVmw4QnNVVmRzT0ZUVjV1QVdIdVdSeXp5a0dZaGhOTDdpbXdFaE9xR1hxaFBaMUhjbjJkYXhmNW5WaE44dkRuWGZqdVhTMkNJdFVxZjNHMXZhYkxwMVdRSDV1Q1d3QVFzWUxkSSt6d21RMVpNWk13Q25yZy9Bd3QxOWNQQjVCTDYwSGRVODI1MlBDa2Fna3EybzQ5eUxaM0d2R2NIZkNobzhnVlBMU0l1VGhndW1UWGtUY2Fsd0ZvMUthTEV2QS9VK1hDUW01MUg1TThxM1Eyc04zR1ZKSWpUV25yWDQrdG15a2wxOGo1dWRtT0loZjUwNlVEY1lYWDZqaW5KNzltYWptaHphVmpZcmNlOUpQSXgwMU5wZ2l1Z05FR092N3RxdHVsZjlvUHI4bmJxSWJZR1dacmdEMzdGcHUvd1FQVm9hZjExIiwiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUdaNjVaTVdSU0lTV1M0UkI2M1pFQktKREpQTUlDSTVXVTZTRFlUVTdDWktERkFTUkFBUjdXTllSVFZLWVdSVVJDQzc3RTJFSUdYQkJVVE8zUkVLREdXTUxKRE43T0RBSEtXSkxKQ1ROSE4zQ1UzTFZYRE1HUkpKM0hJWE1XUkxWVDZENU9GV05ZWFo3M0o3WTZUQ09OUlhZTDJPVEpIUlE3U1VHUUtFQkJJUE5WSVlaMzVXSSIsInVzZXJJZCI6ImFtem4xLmFzay5hY2NvdW50LkFIN0ZMT1U3REJGUldWSUVOVFY3VlQ3RU1RTFBBR1lNRlU0WVVUSTZPU0JDSzZHT0tYV05RNkJJM0JQWlBFTU4yVFFGWEdaQ080M0tYQjNISk5WSlBCSklMUEVETEdJQU1RSzJESzNDNDJTNUZCUENRU042QjQ2Rk1RREFURlNDTDQyWUNGMjVQUjVDRlBHSFlVRklESUpIWkFKUklHTVo1QkdaTVU3Rk5KQjRJNktCVkRGNU4yV0lYQ0lHNllNVjJYNFpPM1FFVEdBMjNIUSJ9fQ.X2fY3XTWW8zRZtwE6km2AIaSnhaAfSLKYqzgwlZrui6OyCS03Lfh1dJWHg4sZxTZqWyssV7VFWErW-gTZFUdkagtbbknuZQ3qlVQlwpZPaKhKBYC9VBDfmnGtjjDDCAAUyvB8ZIInbuxsrZ6DwYtuj5sa5_wGSfc0s2THQqP9Azklgk5UobwMN0iWsrhDSXy4guB4KaEJscD8_OLr2ZnbvWqy3tAPv3zfEsb8OmnOC7FBMHHgN-aCIRubnZNu8YA2Xtf-usOn1wVAjaIwEdlfgrOCRfFpZc3l7tfHTfX9HfLerRFh_IWQWc61DVfQZhyH4yeH5fdKUVDMels4zXlKQ"
}
},
"request": {
"type": "SessionEndedRequest",
"requestId": "amzn1.echo-api.request.e6d2bca6-4680-4367-8bb1-104e038c35ba",
"timestamp": "2021-12-03T02:22:58Z",
"locale": "en-US",
"reason": "ERROR",
"error": {
"type": "INVALID_RESPONSE",
"message": "An exception occurred while dispatching the request to the skill."
}
}
}
Here is my current code, hopefully someone can help me

After hours of researching and github searches, this is the github repo you need to look at if you are willing to host your skill locally using REST API
https://github.com/hanstxu/alexa_endpoint_js

Related

Why is watcher giving errors?

I want to send slack notifications to a channel as soon as any log with loglevel ERROR appears in my index. I have configured watcher in the following way but it is giving me errors. The slack message must have the log message.
I am not able to configure this exactly.
{
"trigger": {
"schedule": {
"interval": "10s"
}
},
"input": {
"search": {
"request": {
"search_type": "query_then_fetch",
"indices": [
"index-log*",
"index-beat*"
],
"rest_total_hits_as_int": true,
"body": {
"query": {
"match": {
"loglevel": "ERROR"
},
"range": {
"#timestamp": {
"from": "{{ctx.trigger.scheduled_time}}||-5m",
"to": "{{ctx.trigger.triggered_time}}"
}
}
}
}
}
}
},
"condition": {
"compare": {
"ctx.payload.hits.total": {
"gt": 0
}
}
},
"actions": {
"send_trigger": {
"webhook": {
"scheme": "https",
"host": "hooks.slack.com",
"port": 443,
"method": "post",
"path": "/services/XXXX/XXXX/XXXX",
"params": {},
"headers": {
"Content-type": "application/json"
},
"body": """{ "text": "{{ctx.payload}}"}"""
}
}
}
}
below is the structure of my logs in kibana
{
"_index": "index-beat",
"_type": "_doc",
"_id": "P3Toa34B1LVeuWotaVOY",
"_version": 1,
"_score": 1,
"_source": {
"#timestamp": "2022-01-18T06:38:19.559Z",
"name": "communication",
"loglevel": "ERROR",
"log": {
"file": {
"path": "/home/ubuntu/abc/abc/logs/communication.log"
},
"offset": 0
},
"timestamp": "2022-01-18T06:38:15.384279",
"exception": {
"ex_type": "None",
"ex": "None",
"tb": ""
},
"message": "{'err': 'Test'}"
},
"fields": {
"exception.ex_type": [
"None"
],
"loglevel.keyword": [
"ERROR"
],
"name.keyword": [
"communication"
],
"log.offset": [
0
],
"message": [
"{'err': 'Test'}"
],
"exception.tb": [
""
],
"exception.ex": [
"None"
],
"#timestamp": [
"2022-01-18T06:38:19.559Z"
],
"exception.tb.keyword": [
""
],
"loglevel": [
"ERROR"
],
"log.file.path": [
"/home/ubuntu/abc/abc/logs/communication.log"
],
"message.keyword": [
"{'err': 'Test'}"
],
"name": [
"communication"
],
"exception.ex_type.keyword": [
"None"
],
"exception.ex.keyword": [
"None"
],
"log.file.path.keyword": [
"/home/ubuntu/abc/abc/logs/communication.log"
],
"timestamp": [
"2022-01-18T06:38:15.384Z"
]
}
}
Please help me out in this one.

Can I get the user email within a Velocity template of AWS Amplify?

When I query a resolver in my GraphQL API, in which I have added a $util.error($ctx) to return the context object, I get the following result (removed unnecessary values).
{
"data": {
"listXData": null
},
"errors": [
{
"message": {
"arguments": {},
"args": {},
"info": {
"fieldName": "listXData",
"variables": {},
"parentTypeName": "Query",
"selectionSetList": [
"items",
"items/id",
"items/createdAt",
"items/updatedAt",
"nextToken"
],
"selectionSetGraphQL": "{\n items {\n id\n createdAt\n updatedAt\n }\n nextToken\n}"
},
"request": {...},
"identity": {
"sub": "",
"issuer": "",
"username": "013fe9d2-95f7-4885-83ec-b7e2e0a1423f",
"sourceIp": "",
"claims": {
"origin_jti": "",
"sub": "",
"event_id": "",
"token_use": "",
"scope": "",
"auth_time": ,
"iss": "",
"exp": ,
"iat": ,
"jti": "",
"client_id": "",
"username": "013fe9d2-95f7-4885-83ec-b7e2e0a1423f"
},
"defaultAuthStrategy": "ALLOW"
},
"stash": {},
"source": null,
"result": {
"items": [],
"scannedCount": 0,
"nextToken": null
},
"error": null,
"prev": {
"result": {}
}
},
"errorType": null,
"data": null,
"errorInfo": null,
"path": [
"listXData"
],
"locations": [
{
"line": 2,
"column": 3,
"sourceName": "GraphQL request"
}
]
}
]
}
As you can see, the username is an ID, however I would prefer to (also) have the email. Is it possible to get the user email (within the Velocity template)?
Let me know if I need to add more details or if my question is unclear.
The identity context only returns back the Cognito username for the user pool. You will need to setup pipeline functions to perform additional queries to get your user information. Here is one intro to setting them up.
At this point, it seems that it is not possible to do this purely by vtl.
I have implemented it using a lambda function, as follow:
Lambda function (node):
/* Amplify Params - DO NOT EDIT
ENV
REGION
Amplify Params - DO NOT EDIT */
const aws = require('aws-sdk')
const cognitoidentityserviceprovider = new aws.CognitoIdentityServiceProvider({
apiVersion: '2016-04-18',
region: 'eu-west-1'
})
exports.handler = async (context, event, callback) => {
if (!context.identity?.username) {
callback('Not signed in')
}
const params = {
'AccessToken': context.request.headers.authorization
}
const result = await cognitoidentityserviceprovider.getUser(params).promise()
const email = result.UserAttributes.find(attribute => attribute.Name === 'email')
callback(null, JSON.stringify({ email }))
}
CustomResources.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "An auto-generated nested stack.",
"Metadata": {...},
"Parameters": {...},
"Resources": {
"GetEmailLambdaDataSourceRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": {
"Fn::If": [
"HasEnvironmentParameter",
{
"Fn::Join": [
"-",
[
"GetEmail17ec",
{
"Ref": "GetAttGraphQLAPIApiId"
},
{
"Ref": "env"
}
]
]
},
{
"Fn::Join": [
"-",
[
"GetEmail17ec",
{
"Ref": "GetAttGraphQLAPIApiId"
}
]
]
}
]
},
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "appsync.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Policies": [
{
"PolicyName": "InvokeLambdaFunction",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction"
],
"Resource": {
"Fn::If": [
"HasEnvironmentParameter",
{
"Fn::Sub": [
"arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:GetEmail-${env}",
{
"env": {
"Ref": "env"
}
}
]
},
{
"Fn::Sub": [
"arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:GetEmail",
{}
]
}
]
}
}
]
}
}
]
}
},
"GetEmailLambdaDataSource": {
"Type": "AWS::AppSync::DataSource",
"Properties": {
"ApiId": {
"Ref": "AppSyncApiId"
},
"Name": "GetEmailLambdaDataSource",
"Type": "AWS_LAMBDA",
"ServiceRoleArn": {
"Fn::GetAtt": [
"GetEmailLambdaDataSourceRole",
"Arn"
]
},
"LambdaConfig": {
"LambdaFunctionArn": {
"Fn::If": [
"HasEnvironmentParameter",
{
"Fn::Sub": [
"arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:GetEmail-${env}",
{
"env": {
"Ref": "env"
}
}
]
},
{
"Fn::Sub": [
"arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:GetEmail",
{}
]
}
]
}
}
},
"DependsOn": "GetEmailLambdaDataSourceRole"
},
"InvokeGetEmailLambdaDataSource": {
"Type": "AWS::AppSync::FunctionConfiguration",
"Properties": {
"ApiId": {
"Ref": "AppSyncApiId"
},
"Name": "InvokeGetEmailLambdaDataSource",
"DataSourceName": "GetEmailLambdaDataSource",
"FunctionVersion": "2018-05-29",
"RequestMappingTemplateS3Location": {
"Fn::Sub": [
"s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/pipelineFunctions/${ResolverFileName}",
{
"S3DeploymentBucket": {
"Ref": "S3DeploymentBucket"
},
"S3DeploymentRootKey": {
"Ref": "S3DeploymentRootKey"
},
"ResolverFileName": {
"Fn::Join": [
".",
[
"InvokeGetEmailLambdaDataSource",
"req",
"vtl"
]
]
}
}
]
},
"ResponseMappingTemplateS3Location": {
"Fn::Sub": [
"s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/pipelineFunctions/${ResolverFileName}",
{
"S3DeploymentBucket": {
"Ref": "S3DeploymentBucket"
},
"S3DeploymentRootKey": {
"Ref": "S3DeploymentRootKey"
},
"ResolverFileName": {
"Fn::Join": [
".",
[
"InvokeGetEmailLambdaDataSource",
"res",
"vtl"
]
]
}
}
]
}
},
"DependsOn": "GetEmailLambdaDataSource"
},
"IsOrganizationMember": {
"Type": "AWS::AppSync::FunctionConfiguration",
"Properties": {
"FunctionVersion": "2018-05-29",
"ApiId": {
"Ref": "AppSyncApiId"
},
"Name": "IsOrganizationMember",
"DataSourceName": "PermissionsPerOrganizationTable",
"RequestMappingTemplateS3Location": {
"Fn::Sub": [
"s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/Query.isOrganizationMember.req.vtl",
{
"S3DeploymentBucket": {
"Ref": "S3DeploymentBucket"
},
"S3DeploymentRootKey": {
"Ref": "S3DeploymentRootKey"
}
}
]
},
"ResponseMappingTemplateS3Location": {
"Fn::Sub": [
"s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/Query.isOrganizationMember.res.vtl",
{
"S3DeploymentBucket": {
"Ref": "S3DeploymentBucket"
},
"S3DeploymentRootKey": {
"Ref": "S3DeploymentRootKey"
}
}
]
}
}
},
"OrganizationAccessPipeline": {
"Type": "AWS::AppSync::Resolver",
"Properties": {
"ApiId": {
"Ref": "AppSyncApiId"
},
"TypeName": "Query",
"Kind": "PIPELINE",
"FieldName": "listXData",
"PipelineConfig": {
"Functions": [
{
"Fn::GetAtt": [
"InvokeGetEmailLambdaDataSource",
"FunctionId"
]
},
{
"Fn::GetAtt": [
"IsOrganizationMember",
"FunctionId"
]
}
]
},
"RequestMappingTemplate": "{}",
"ResponseMappingTemplate": "$util.toJson($ctx.result)"
}
}
},
"Conditions": {...},
"Outputs": {...}
}
The lambda is created with the CLI and IsOrganizationMember is a regular VTL which has the user email in the $context.prev.result.

Actions-on-Google can not get UPDATES_USER_ID on Dialogflow SDK

I'm setting up an action which uses push notifications. Yet, on firebase I can't get "UPDATES_USER_ID" of user to save. It returns "undefined".
I followed the guide on this link and here is my code to get UPDATES_USER_ID.
app.intent('Setup', (conv, params) => {
conv.ask(new UpdatePermission({
intent: "notificationResponseIntent"
}));
});
app.intent("FinishNotificationSetup", (conv, params) => {
if (conv.arguments.get('PERMISSION')) {
conv.data.GoogleUserID = conv.arguments.get("UPDATES_USER_ID");
console.log(conv.data.GoogleUserID);
conv.ask("some response....");
}
});
And here is my webhook request when FinishNotificationSetup intent is invoked.
{
"responseId": "2f425fe5-db42-47dc-90a1-c9bc85f725d2",
"queryResult": {
"queryText": "actions_intent_PERMISSION",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"outputContexts": [
{
"name": "projects/projectname/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/actions_capability_screen_output"
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/actions_intent_permission",
"parameters": {
"PERMISSION": true,
"text": ""
}
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/_actions_on_google",
"lifespanCount": 98,
"parameters": {
"data": "{\"***":\"***",\"***":\"***"}"
}
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/actions_capability_account_linking"
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/actions_capability_audio_output"
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/google_assistant_input_type_keyboard"
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/actions_capability_web_browser"
},
{
"name": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA/contexts/actions_capability_media_response_audio"
}
],
"intent": {
"name": "projects/projectname-10c22/agent/intents/a12b6d3f-0f24-45e9-a1b2-5649083831b0",
"displayName": "FinishNotificationSetup"
},
"intentDetectionConfidence": 1,
"languageCode": "tr"
},
"originalDetectIntentRequest": {
"source": "google",
"version": "2",
"payload": {
"isInSandbox": true,
"surface": {
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.ACCOUNT_LINKING"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
}
]
},
"requestType": "SIMULATOR",
"inputs": [
{
"rawInputs": [
{
"inputType": "KEYBOARD"
}
],
"arguments": [
{
"textValue": "true",
"name": "PERMISSION",
"boolValue": true
},
{
"name": "text"
}
],
"intent": "actions.intent.PERMISSION"
}
],
"user": {
"lastSeen": "2019-04-30T07:23:23Z",
"permissions": [
"UPDATE"
],
"locale": "tr-TR",
"userId": "ABwppHHCEdtf23ZaNg0DaCv3fvshSUXUvYGXHe6kR7jbKacwIS6vDBBL7YXbN70jYa8KaXWZqbsyhFFSdsYLiw"
},
"conversation": {
"conversationId": "ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA",
"type": "ACTIVE",
"conversationToken": "[\"_actions_on_google\"]"
},
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
}
]
}
},
"session": "projects/projectname-10c22/agent/sessions/ABwppHGD33Tyho41g9Mr2vzxePlskNmvOzCTxUiDGzENcl3C7RQs94aOQ8ae_DUlOApR0VBO9DuwAWdWr2frAA"
}
To send notification, I've been using userID instead of UPDATES_USER_ID and it is working. Yet, it will be deprecated soon. So, I need to find a solution to get this ID and couldn't make it working. What do I need to do to get this ID?
I've found solution for this problem. While getting UPDATES_USER_ID conv.arguments.get() only works for first attempt. So, while building your action you must save it. If you didn't store or save, you can reset your profile and try again, you will be able to get.
app.intent("FinishNotificationSetup", (conv, params) => {
if (conv.arguments.get('PERMISSION')) {
if(!conv.user.storage.GoogleUserID)
{
conv.user.storage.GoogleUserID = conv.arguments.get("UPDATES_USER_ID");
//For best case
//store ID in your db.
}
console.log(conv.user.storage.GoogleUserID);
conv.ask("some response....");
}
});
For best case, try saving this to your database because conv.user.storage does not work sometimes.

Using Pact.eachLike() when array contents vary for each item

Hi I have a Consumer test produced using Pact NPM https://www.npmjs.com/package/pact
I use the following code to generate a pact.json:
provider
.addInteraction({
state: 'test',
uponReceiving: 'a test,
withRequest: {
method: 'GET',
path: '/test'
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json' }
body: {
"company": like("My big company"),
"factories": eachLike({
"location": like("Sydney"),
"capacity": like(5)
},{min:1})
}
}
})
.then(function(){ done(); });
It generates the following testconsumer-testprovider.json file:
{
"consumer": {
"name": "TestConsumer"
},
"provider": {
"name": "TestProvider"
},
"interactions": [
{
"description": "a request for loans",
"providerState": "broker is logged in, list all loans",
"request": {
"method": "GET",
"path": "/test"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/vnd.hal+json"
},
"body": {
"company": "My big company",
"factories": [
{
"location": "Sydney",
"capacity": 5
}
]
},
"matchingRules": {
"$.headers.Content-Type": {
"match": "regex",
"regex": "application\\/.*json.*"
},
"$.body.company": {
"match": "type"
},
"$.body.factories": {
"min": 1
},
"$.body.factories[*].*": {
"match": "type"
},
"$.body.factories[*].location": {
"match": "type"
},
"$.body.factories[*].capacity": {
"match": "type"
}
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
}
}
}
However when we test against the following provided output we get an error with the geographicCoords because it's an unexpected key/value:
{
"company": "My Company",
"factories": [
{
"location": "Sydney",
"capacity": 5
},
{
"location": "Sydney",
"geographicCoords": "-0.145,1.4445",
"capacity": 5,
}
]
}
So is there a was to allow unexpected key/values in arrays because we're only test for required key/values and we don't want out pact tests to fail in future when new values are added to our providers.
The scenario you are describing is supported, see https://github.com/pact-foundation/pact-js/tree/master/examples/e2e for an example.
If you were to remove, say the eligibility object and run the tests everything still works.
If you are still having troubles, please raise a defect on the pact-js repository and we'll get to the bottom of it.

Deploying a logic app using ARM templates/powershell

How can I Deploy a logic app that calls a SQL DB stored procedure? I've tried the following action.
"actions": {
"Execute_stored_procedure": {
"conditions": [ ],
"inputs": {
"body": null,
"host": {
"api": {
"runtimeUrl": "https://logic-apis-northcentralus.azure-apim.net/apim/sql"
},
"connection": {
"name": "<sql connection string>"
}
},
"method": "post",
"path": "/datasets/default/procedures/#{encodeURIComponent(encodeURIComponent(string('<stored-procedure-name>')))}"
},
"type": "apiconnection"
}
}
When I deploy this template, the logic app get's created but it's throwing errors or the SQL Connection action is not showing up on the design view. What am I doing wrong here? Is Logic App for calling SQL Stored Proc supported by arm currently?
Here is a sample template for LogicApp ARM template + 'connections' resource
https://blogs.msdn.microsoft.com/logicapps/2016/02/23/deploying-in-the-logic-apps-preview-refresh/
https://github.com/jeffhollan/logicapps-deployments/blob/master/ftp_to_blob.json
I've finally figured this out from #TusharJ links and I'm posting the template I've used below to configure a LogicApp that calls a SQL DB stored procedure in specific intervals.
resources:
[
{
"type": "Microsoft.Web/connections",
"apiVersion": "2015-08-01-preview",
"location": "[resourceGroup().location]",
"name": "sqlconnector",
"properties": {
"api": {
"id": "[concat('subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/sql')]"
},
"displayName": "sqlconnector",
"parameterValues": {
"sqlConnectionString": "<sql db connection string>"
}
}
},
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2015-08-01-preview",
"name": "[parameters('logicAppName')]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "LogicApp"
},
"properties": {
"sku": {
"name": "[parameters('workflowSkuName')]",
"plan": {
"id": "[concat(resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('svcPlanName'))]"
}
},
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2015-08-01-preview/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": { },
"type": "Object"
}
},
"triggers": {
"recurrence": {
"type": "recurrence",
"recurrence": {
"frequency": "Hour",
"interval": 1
}
}
},
"actions": {
"Execute_stored_procedure": {
"conditions": [ ],
"inputs": {
"body": null,
"host": {
"api": {
"runtimeUrl": "[concat('https://logic-apis-', resourceGroup().location, '.azure-apim.net/apim/sql')]"
},
"connection": {
"name": "#parameters('$connections')['sql']['connectionId']"
}
},
"method": "post",
"path": "/datasets/default/procedures/#{encodeURIComponent(encodeURIComponent(string('[dbo].[<Stored Proc Name>]')))}"
},
"type": "apiconnection"
}
},
"outputs": { }
},
"parameters": {
"$connections": {
"value": {
"sql": {
"connectionId": "[resourceId('Microsoft.Web/connections', 'sqlconnector')]",
"connectionName": "sqlconnector",
"id": "[reference(concat('Microsoft.Web/connections/', 'sqlconnector'), '2015-08-01-preview').api.id]"
}
}
}
}
}
}
]
Things may have changed in the API since the previous answer was given. Here is what worked for me as of 10/2016. Note: I used parameters (definitions not shown) for many of the variables:
{
"type": "Microsoft.Web/connections",
"apiVersion": "2015-08-01-preview",
"location": "[parameters('location')]",
"name": "[variables('sql_conn_name')]",
"properties": {
"api": {
"id": "[concat(subscription().id, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/sql')]"
},
"displayName": "sql_connection",
"parameterValues": {
"server": "[concat(variables('dbserver_unique_name'), '.database.windows.net')]",
"database": "[parameters('databases_name')]",
"authType": "windows",
"username": "[parameters('databases_admin_user')]",
"password": "[parameters('databases_admin_password')]"
}
}
},
{
"type": "Microsoft.Logic/workflows",
"name": "[variables('logic_app_name')]",
"apiVersion": "2016-06-01",
"location": "[parameters('location')]",
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": { },
"type": "Object"
}
},
"triggers": {
"Recurrence": {
"recurrence": {
"frequency": "Hour",
"interval": 1
},
"type": "Recurrence"
}
},
"actions": {
"Execute_stored_procedure": {
"runAfter": { },
"type": "ApiConnection",
"inputs": {
"body": {
"timeoffset": "-4"
},
"host": {
"api": {
"runtimeUrl": "[concat('https://logic-apis-', parameters('location'), '.azure-apim.net/apim/sql')]"
},
"connection": {
"name": "#parameters('$connections')['sql']['connectionId']"
}
},
"method": "post",
"path": "/datasets/default/procedures/#{encodeURIComponent(encodeURIComponent('[dbo].[usp_UpdateHourlyOos]'))}"
}
}
},
"outputs": { }
},
"parameters": {
"$connections": {
"value": {
"sql": {
"connectionId": "[concat(subscription().id, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/connections/', variables('sql_conn_name'))]",
"connectionName": "[variables('sql_conn_name')]",
"id": "[concat(subscription().id,'/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/sql')]"
}
}
}
}
},
"resources": [ ],
"dependsOn": [
"[resourceId('Microsoft.Web/connections', variables('sql_conn_name'))]"
]
}

Resources