How do I initiate a conversation with AWS LEX from node js? - node.js

My context is this: I am attempting to build a chat bot into my Mozilla Hubs client, which is a node js / React project. I have a lex bot created on AWS, and I have installed the client-lex-runtime-v2 package and can import it successfully, but I have no idea how to set up a StartConversationCommand, give it credentials, etc. Most of the javascript examples seem to go the other way, where Lex calls a lambda function after processing a request, but I have user input in my app and I need to send it to Lex, and then deliver the resulting text back to the user inside my application.
This seems like very basic Lex usage - if anyone could point me to a code example I would be most grateful.

John,
You need to make use of the LexRuntimeV2Client in the SDK as demonstrated here.
From the linked documentation, the below is how you import and instantiate a new client:
import { LexRuntimeV2Client, DeleteSessionCommand } from "#aws-sdk/client-lex-runtime-v2";
const client = new LexRuntimeV2Client({ region: "REGION" });
Once configured with your respective AWS environment details, credentials etc you will be able to invoke your Lex bot (again, from the linked documentation):
try {
const data = await client.send(command);
// process data.
} catch (error) {
// error handling.
} finally {
// finally.
}
Take a look at this sample repo on GitHub as well: aws-lex-web-ui

So for anyone else stuck where I was, I cannot say this is the right way to do it, because I never did get it working, but the closest I got to at least forming up my credentials and trying to make a connection was this:
const client = new LexRuntimeV2Client({
region: "us-east-1",
credentials: new AWS.Credentials({
accessKeyId: "my_IAM_access_key_id",
secretAccessKey: "my_secret_access_key"
})
});
const lexparams = {
"botAliasId": "my alias_id",
"botId": "bot_id_from_lex",
"localeId": "en_US",
"inputText": "hello, this is a test sample",
"sessionId": "some_session_id"
};
let cmd = new StartConversationCommand(lexparams);
try {
const data = await client.send(cmd);
console.log("Success. Response is: ", data.message);
} catch (err) {
console.log("Error responding to message. ", err);
}
As said, buyer beware, and best of luck out there! I hope this might help somebody in some slight way. We taking a momentary break on this problem until a member of our team with better aws fu can take a look at it. :-)

This is working for me:
var AWS = require('aws-sdk');
const { LexRuntimeV2 } = require("#aws-sdk/client-lex-runtime-v2");
const lexruntime = new LexRuntimeV2({
region: "us-west-2", // Set your Bot Region
credentials: new AWS.Credentials({
accessKeyId: "***", // Add your access IAM accessKeyId
secretAccessKey: "***" // Add your access IAM secretAccessKey
})
});
const lexparams = {
"botAliasId": "HG****", // Enter the botAliasId
"botId": "HG***", // Enter the botId
"localeId": "en_US",
"text": "Book Car",
"sessionId": "some_session_id"
};
lexruntime.recognizeText(lexparams, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});

Related

AWS-SNS publish() method not sending any messages to phone number

I have used aws-sdk in node express to send the verification code to the phone number I referred this docs to implement it. here I get the response but do not get any messages on the phone.
const AWS = require("aws-sdk");
AWS.config.update({
region: "region",
accessKeyId: "ACCESS_KEY",
secretAccessKey: "SECRET_KEY",
});
router.post("/", async (req, res) => {
let phone_no = "+91876214****";
let random = Math.floor(100000 + Math.random() * 900000);
const YOUR_MESSAGE = `Your verification code is ${random}`;
let params = {
Message: YOUR_MESSAGE,
PhoneNumber: phone_no,
MessageAttributes: {
"AWS.SNS.SMS.SMSType": {
DataType: "String",
StringValue: "Transactional",
},
};
let publishTextPromise = new AWS.SNS({ apiVersion: "2010-03-31" })
.publish(params)
.promise();
publishTextPromise
.then(function (data) {
return res.json({ id: data.MessageId, otp: random });
})
.catch(function (err) {
return res.send(err.stack);
});
});
is anything I'm doing wrong, new to this aws-sns concept.
here i logged the publishTextPromise i get response as Promise { <pending> }
If you get Success result from api but message is not received. You need to check SNS logs.
On SNS console, you can see Text messaging (SMS) under Mobile section. If you don't enable status logging, firstly edit preferences on Delivery status logs section then on new page create an IAM Role (SNSSuccessFeedback) with Success sample rate 100%.
You can find error on cloudwatch.
Potential problem. You account is in the SMS sandbox in the region which you used.
If you see any message like ☝️, You can add your phone number on sandbox destination phone number.
Then sandbox will send you a verify code, when you put it on AWS console. Then you will be able to receive messages from SNS.

Nodejs - AWS SNS publish is called, but message is not being sent

I'm trying to publish a SNS message to a single user.
The message is working when I manually press the "Publish Endpoint" button in the AWS console, but I'm trying to send it programmatically using the SNS nodejs SDK.
I have made sure to create a single IAM role giving full access permissions to SNS.
I have made sure to configure it:
const AWS = require("aws-sdk");
AWS.config.update({
region: process.env.AWS_REGION,
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
I first create a platform endpoint using sns.createPlatformEndpoint(endPointParams) and it works fine so my IAM role is not an issue.
Using the result from that call, I use the data to create publishParams to make a call right after creating the endpoint:
let payload = {
user : "Hihih test",
shopping_list : "shopping_item"
};
let endPointParams = {
PlatformApplicationArn: process.env.REACT_APP_SNS_ARN,
Token: req.body.device_token
}
const createEndPoint = sns.createPlatformEndpoint(endPointParams).promise();
createEndPoint.then(data => {
console.log(data.EndpointArn);
console.log(JSON.stringify(payload));
let publishParams = {
Message: JSON.stringify(payload),
MessageStructure: 'json',
TargetArn: data.EndpointArn
};
sns.publish(publishParams, (err, result1) =>{
console.log("Success");
});
return;
}).then(result => {
res.status(200).send("Success sending invite to user.");
}).catch(err => {
console.log(err);
res.status(500).send("Something went wrong sending the invite.");
});
});
The console.log("Success"); inside sns.publish() is being fired, but on the client side, the app does not receive a message. I have also tried multiple times to manually call "Publish Message" in the console and it works fine.
So what could my issue be? I think it's something wrong with my code.
When using SNS with GCM you need to structure your JSON payload with the keys GCM and default or it will throw an err.
var payload = {
default: 'Hello World',
GCM: {
notification: {
title: 'Hello World',
body: 'Notification Body'
// other configs can be put here
}
}
};

Using AWS Lambda to delete a Cognito User

I want to give user's the ability to delete their account in my android app. I already set up a login/sig up functionality with AWS Amplify and a AWS Cognito User Pool. But Amplify doesn't provide a "delete User" functionality, so I wanted to use a lambda function to delete a user from my cognito user pool.
The function will be called when the user clicks on "delete my account" in the app. To test the function, I use a hard coded username in the Lambda function, instead of passing one into the function. But even that doesn't work. After deploying the Lambda function, I run the function by clicking on "Test" in the console. The console then shows Execution result: succeeded but the response is null. I would either epect a Status 200 or 400 as response. And in the CloudWatch logs of the Execution I can only see my first log statement ("I was here"), the other two don't show up. And in the Cognito Console the user is still there.
This is my Lambda Code (Node.js):
const AWS = require('aws-sdk');
console.log("I was here");
var params = {
UserPoolId: 'syz****f-dev',
Username: '5b53****138'
};
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({
"region": 'eu-central-1',
});
exports.handler = async (event) => {
cognitoidentityserviceprovider.adminDeleteUser(params, function(err, data) {
if (err) {
var response = {
statusCode: 400,
body: JSON.stringify('Didnt work!'),
};
console.log(err, err.stack);
return response;
}
else {
response = {
statusCode: 200,
body: JSON.stringify('yeah!'),
};
console.log(data);
return response;
}
});
};
The user "5b53....138" is still there in my Cognito User Pool "syz....f-dev" after I test this function:
This is the log file that I found in Cloudwatch:
My Lambda Function has a role with these 3 policies and I used the IAM Policy Simulator and the action AdminDeleteUser is allowed with AmazonCognitoAuthenticatedIdentities, so this shouldn`t be the problem:
AmazonCognitoAuthenticatedIdentities
AmazonCognitoPowerUser
AWSLambdaBasicExecutionRole
In CloudWatch I can see that the function got invoked.
First of all, your user pool id is wrong, find the correct on by opening your Cognito user pool: The first thing you see when opening your user pool in the console is the id:
It starts with your region followed by a _, in your case eu-central-1_.
Then try using this code instead of your adminDeleteUser function. Then it should work:
try {
const data = await cognitoidentityserviceprovider.adminDeleteUser(params).promise();
} catch (error) {
console.log(error);
}

Can I run Cognito in a Lambda function?

I want to sign up users with Cognito in a Lambda function. However I am receiving "TypeError: fetch is not a function"
My code is basically step 3 in this. However I keep getting the above-mentioned error, even though I have node-fetch installed. From what I understand, the Cognito SDK makes use of fetch. So is this simply not possible? Will I need to spin up a Node server?
const AWS = require("aws-sdk");
const AmazonCognitoIdentity = require("amazon-cognito-identity-js");
//Configuring pool data of Cognito Identity Pool
const poolData = {
UserPoolId: "us-east-2_aCvZbFzeS",
ClientId: "4nv2krchr77pbrq3cpk0q0kknu"
};
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
AWS.config.region = "us-east-2";
const attributeList = [];
attributeList.push(
new AmazonCognitoIdentity.CognitoUserAttribute({
Name: "email",
Value: "sampleEmail#gmail.com"
})
);
userPool.signUp(
"sampleEmail#gmail.com",
"SamplePassword123",
attributeList,
null,
function(err, result) {
if (err) {
console.log(err);
return;
}
const cognitoUser = result.user;
console.log("user name is " + cognitoUser.getUsername());
}
);
const data = JSON.parse(event.body);
const headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true
};
const response = {
statusCode: 200,
headers: headers,
"Content-Type": "application/json",
body: JSON.stringify(data.age)
};
callback(null, response);
};
//I keep receiving this error when attempting to hit the endpoint with Postman:
"errorMessage": "Uncaught error in your 'hello' handler",
"errorType": "TypeError",
"stackTrace": [
"TypeError: fetch is not a function"
You can definitely use Cognito from Lambda! Source: have done it.
You may not be able to use the AWS Cognito JS SDK from Lambda nicely, though.
The AWS Cognito JS SDK appears to be designed for client-side applications, where fetch is a built-in. You have installed node-fetch, but the SDK is not loading it because it doesn't think it needs to, because it is expecting it to be built-in.
I see two options:
If you aren't particularly attached to JS, you could use another language where you are confident that the library is designed and tested for server-side applications.
If you are attached to JS or have a large sunk cost, you could hack up the AWS Cognito JS SDK locally before deploying the code to Lambda to make it require node-fetch or otherwise make it functional server-side.
This thread has a good description of the same issue and some workarounds; probably the best one for you is:
global.fetch = require('node-fetch')
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
in your script, which should make it appear as a built-in to the SDK's code without hacking up the internals.

Using AWS API Gateway SDK in Node.JS causes issues

So I am trying to follow the AWS API Gateway SDK tutorial on setting up a secure connection between the NodeJS App and API Gateway link here.
My test function looks like something like below:
require('./lib/apigClient');
require('./lib/axios/dist/axios.standalone');
require('./lib/CryptoJS/rollups/hmac-sha256');
require('./lib/CryptoJS/rollups/sha256');
require('./lib/CryptoJS/components/hmac');
require('./lib/CryptoJS/components/enc-base64');
require('./lib/url-template/url-template');
require('./lib/apiGatewayCore/sigV4Client');
require('./lib/apiGatewayCore/apiGatewayClient');
require('./lib/apiGatewayCore/simpleHttpClient');
require('./lib/apiGatewayCore/utils');
var body = {
"type": "the_best_kind",
"status": "processed",
"name": "test123"
};
export function getRatingsTest(req, res) {
var apigClient = apigClientFactory.newClient({
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY',
sessionToken:'SESSION_TOKEn', //OPTIONAL: If you are using temporary credentials you must include the session token
region: 'eu-west-1' // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1
});
console.log('NEW CLIENT =====', apigClient)
apigClient.calcRatingPost(null, body, null)
.then(function(result){
//This is where you would put a success callback
}).catch( function(result){
//This is where you would put an error callback
});
return res.json({test: 123})
}
I keep getting error such a apiGateway is not defined, CryptoJs is not defined and so on. All the 11 javascript files are not modular which is unfortunate.
What is the best approach for getting this to work in NodeJS?
I also tried the aws-api-gateway-client npm package but no luck yet.

Resources