I am sending the OTP using AWS SNS service when in a lambda function my code is this
const otp = generateOTP();
const message = `Your XXXX Verification Code is ${otp} .`;
var params = {
Message: message,
PhoneNumber: "+91xxxxxxxxxx",
};
AWS.config.update({region: 'ap-south-1'});
var publishTextPromise = new AWS.SNS({apiVersion: '2022-04-01'}).publish(params).promise();
return new Promise((resolve, reject) => {
publishTextPromise.then((data) => {
console.log("MessageID is " + data.MessageId);
const response = {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
};
console.log('Server response function');
resolve(response);
}).catch((error) => { reject(Error(error)); });
});
and i am getting this response when invoking this lambda function
Server response function
{
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"ResponseMetadata": {
"RequestId": "29796d67-f32e-5e42-a761-37a72809164d"
},
"MessageId": "2f8ffee0-7e0d-5cd3-a5b0-a420a52a14dc"
}
}
But I am not receiving the SMS on that number I don't know what is the problem here cause the I am getting resolved response in the console which means the SMS is send but I am not received it.
Do I have to config the sns manual in aws sns mobile -> text messaging or something??
or is their any other way to send verification otp ?
Related
I am having a bit of an issue getting push notifications to be sent remotely from a lambda using AWS pinpoint.
In my application I have the following code:
PushNotification.configure(awsconfig)
PushNotificationIOS.addEventListener('registrationError', console.log)
PushNotification.onRegister(async token => {
console.log('in app registration', token)
PushNotification.updateEndpoint(token)
setRegistrationToken(token)
})
PushNotification.onNotification(notification => {
console.log('in app notification', notification)
if (Platform.OS === 'ios') {
notification.finish(PushNotificationIOS.FetchResult.NoData)
}
})
PushNotification.onNotificationOpened(notification => {
console.log('the notification is opened', notification)
})
const endpointId = Analytics.getPluggable('AWSPinpoint')._config.endpointId
console.log(`endpoint ID: ${endpointId}`)
if (Platform.OS === 'ios') {
PushNotification.requestIOSPermissions()
}
That code runs perfectly and I can take the token that is logged, go to the pinpoint console, and send a "Test Notification" by choosing "Device Tokens" and "APNS Sandbox."
After that, I set up my lambda and added the following code:
const AWS = require('aws-sdk');
async function sendTestNotification() {
console.log("CALLED SEND TEST")
const title = "Test Message"
const message = "This is a message from Pinpoint dynamically delivered via code"
const applicationId = <HARD CODED APPLICATION ID FROM PINPOINT CONSOLE>
const token = <HARD CODED DEVICE TOKEN I USED IN THE TEST NOTIFICATION>
var messageRequest = {
'Addresses': {
[token]: {
'ChannelType' : 'APNS_SANDBOX'
}
},
'MessageConfiguration': {
'APNSMessage': {
'Action': 'OPEN_APP',
'Body': message,
'Priority': 'normal',
'SilentPush': false,
'Title': title,
'TimeToLive': 30
}
}
};
AWS.config.update({ region: 'us-east-1'});
var pinpoint = new AWS.Pinpoint();
var params = {
"ApplicationId": applicationId,
"MessageRequest": messageRequest
}
pinpoint.sendMessages(params, (sendMessagesErr, sendMessagesData) => console.log(sendMessagesErr, sendMessagesData))
}
exports.handler = async (event) => {
console.log('running')
await sendTestNotification();
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
When I test the function, it runs and completes normally with no errors. However, no notifications come through. Initially, I thought it may have to do with permissions, but I have given the lambda full access to Pinpoint via a custom role, and that still did not change the result.
Any help would be much appreciated, as I am not sure where to troubleshoot next.
You haven't set the token in your MessageRequest. You have [token] under addresses:. You need to put the actual APNS token here. (I've put in some random letters in numbers here for an example...
var messageRequest = {
'Addresses': {
'483hgto483gh87egf8o2phqradgq3984hgeorigheg27r': {
'ChannelType' : 'APNS_SANDBOX'
}
},
'MessageConfiguration': {
'APNSMessage': {
'Action': 'OPEN_APP',
'Body': message,
'Priority': 'normal',
'SilentPush': false,
'Title': title,
'TimeToLive': 30
}
}
};
I'm trying to build my first lambda function that triggered by an API gateway request, then sends to Queue service where I included down below: /when I send a request through api gateway, it gives status code: 200 but queue doesn't get any messages/
var AWS = require('aws-sdk');
var sqs = new AWS.SQS();
exports.handler = function(event, context, callback) {
var params = {
MessageBody: JSON.stringify(event),
QueueUrl: 'https://sqs.ap-southeast-1.amazonaws.com/********/****.fifo'
};
sqs.sendMessage(params, function(err, data) {
if (err) {
console.log('error:', "Fail Send Message", +err);
context.done('error', "ERROR Put SQS");
} else {
console.log('data:', data.MessageId);
context.done(null, '');
}
});
}
I have copied the example in the various guides on the internet, including the fairly recent topic on SO:
How to send SMS using Amazon SNS from a AWS lambda function
I've implemented successfully the code from https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/sns-examples-sending-sms.html on my local nodejs server, however when i do the same on Lambda nothing happens, not even console.log???
This is the code i am using in Lambda:
const AWS = require('aws-sdk');
exports.handler = async (event) => {
AWS.config.update({region: 'eu-west-2'});
var params = {
Message: 'TEXT_MESSAGE', /* required */
PhoneNumber: '+1346879',
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("MessageID is " + data.MessageId);
const response = {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
};
console.log('Server response function');
return response;
}).catch(
function(error) {
//console.error(err, err.stack);
const response = {
statusCode: 500,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({error: 'Internal server error', message: error})
};
return response;
});
}
Needless to say i tried various flavours of what seems to be an elementary piece of code...
Logs say exactly this:
2020-10-29T00:29:21.820+00:00 START RequestId: 8dbaedac-1f98-4319-9ac5-acba1d8860c5 Version: $LATEST
2020-10-29T00:29:22.242+00:00 Lambda Insights extension initializing.
2020-10-29T00:29:22.242+00:00 EXTENSION Name: cloudwatch_lambda_agent State: Ready Events: [INVOKE,SHUTDOWN]
2020-10-29T00:29:22.838+00:00 END RequestId: 8dbaedac-1f98-4319-9ac5-acba1d8860c5
2020-10-29T00:29:22.838+00:00
Copy
REPORT RequestId: 8dbaedac-1f98-4319-9ac5-acba1d8860c5 Duration: 594.62 ms Billed Duration: 600 ms Memory Size: 128 MB Max Memory Used: 99 MB Init Duration: 448.90 ms
REPORT RequestId: 8dbaedac-1f98-4319-9ac5-acba1d8860c5 Duration: 594.62 ms Billed Duration: 600 ms Memory Size: 128 MB Max Memory Used: 99 MB Init Duration: 448.90 ms
I have set permissions in the same exact way both on my user and on lambda:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sns:*",
"Resource": "*"
}
]
}
Any thought?
I think that you have to return a promise to ensure all the tasks will be executed till the end.
If your code performs an asynchronous task, return a promise to make sure that it finishes running. When you resolve or reject the promise, Lambda sends the response or error to the invoker.
const AWS = require('aws-sdk');
exports.handler = async (event) => {
AWS.config.update({region: 'eu-west-2'});
var params = {
Message: 'TEXT_MESSAGE', /* required */
PhoneNumber: '+1346879',
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
return new Promise((resolve, reject) => {
// Handle promise's fulfilled/rejected states
publishTextPromise.then((data) => {
console.log("MessageID is " + data.MessageId);
const response = {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
};
console.log('Server response function');
resolve(response);
}).catch((error) => { reject(Error(error)); });
});
}
Check the lambda execution time, try to increase it to 15 mins.
This SNS is having two types of messages 1.Promotional 2.Transactional
By default it choose promotional. If end users is having DND enabled to his number. Then your message will not delivered.
If it is related to transactional use the below object for sending transactional messages.
{
Message: 'Message',
PhoneNumber: '+XXX',
MessageAttributes: {
'AWS.SNS.SMS.SMSType': {
DataType: 'String',
StringValue: 'Transactional'
}
}
I want to return connectionId to a client after the client connect to aws websocket.
I'm using apigwManagementApi.postToConnection to send a response to a client, but I always get an absurd error message.
I already try to debug & search in google, but I can't find a solution for this.
patch.js
require('aws-sdk/lib/node_loader');
var AWS = require('aws-sdk/lib/core');
var Service = AWS.Service;
var apiLoader = AWS.apiLoader;
apiLoader.services['apigatewaymanagementapi'] = {};
AWS.ApiGatewayManagementApi = Service.defineService('apigatewaymanagementapi', ['2018-11-29']);
Object.defineProperty(apiLoader.services['apigatewaymanagementapi'], '2018-11-29', {
get: function get() {
var model = {
"metadata": {
"apiVersion": "2018-11-29",
"endpointPrefix": "execute-api",
"signingName": "execute-api",
"serviceFullName": "AmazonApiGatewayManagementApi",
"serviceId": "ApiGatewayManagementApi",
"protocol": "rest-json",
"jsonVersion": "1.1",
"uid": "apigatewaymanagementapi-2018-11-29",
"signatureVersion": "v4"
},
"operations": {
"PostToConnection": {
"http": {
"requestUri": "/#connections/{connectionId}",
"responseCode": 200
},
"input": {
"type": "structure",
"members": {
"Data": {
"type": "blob"
},
"ConnectionId": {
"location": "uri",
"locationName": "connectionId"
}
},
"required": [
"ConnectionId",
"Data"
],
"payload": "Data"
}
}
},
"shapes": {}
}
model.paginators = {
"pagination": {}
}
return model;
},
enumerable: true,
configurable: true
});
module.exports = AWS.ApiGatewayManagementApi;
index.js
const AWS = require('aws-sdk');
require('./patch.js');
exports.handler = async(event) => {
const connectionId = event.requestContext.connectionId;
const apigwManagementApi = new AWS.ApiGatewayManagementApi({
apiVersion: '2018-11-29',
endpoint: event.requestContext.domainName + '/' + event.requestContext.stage
});
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: connectionId }).promise();
return {};
};
client.js
const WebSocket = require('ws');
const ws = new WebSocket('wss://****');
ws.on('open', () => {
console.log('connected ===================>')
ws.on('message', data => console.warn(`From server: ${data}`));
});
Error in cloudwatch
{
"errorMessage": "410",
"errorType": "UnknownError",
"stackTrace": [
"Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)",
"Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:52:8)",
"Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)",
"Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)",
"Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)",
"Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)",
"AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)",
"/var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10",
"Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)",
"Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)"
]
}
I don't know why, but if I'm trying in a custom route, this code can work.
Does anyone know how to solve this?
I'd suggest to look into this example from AWS, there is on connect response for subprotocol confirmation, but I think any payload can be provided.
The most important bit is the route integration settings in the template, basically, the following two lines in the route integration properties:
IntegrationMethod: POST
ConnectionType: INTERNET
then response will be sent to the connected client.
The only way I've found to make this work is to use a DynamoDB table to store connections, then set up a trigger from the table back to a Lambda function.
There are a few catches though. This Lambda function wont work like your index.js file above. You'll have to use NPM install --save aws-sdk on a folder with your index.js file, zip it and upload it to the lambda function, so that the SDK is localized.
You will also need to set up a user with proper access and put the credentials into a your Lambda function.
Note, if you see a 410 error, that means the connection is no longer there, so you're going in the right direction at that point.
const AWS = require('aws-sdk');
require('./patch.js');
var log = console.log;
AWS.config.update({
accessKeyId: "YOURDATAHERE",
secretAccessKey: "YOURDATAHERE"
});
let send = undefined;
function init() {
const apigwManagementApi = new AWS.ApiGatewayManagementApi({
apiVersion: '2018-11-29',
endpoint: "HARDCODEYOURENDPOINTHERE"
});
send = async (connectionId, data) => {
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: `${data}` }).promise();
}
}
exports.handler = async (event, context) => {
init();
console.log('Received event:', JSON.stringify(event, null, 2));
for (const record of event.Records) {
//console.log(record.eventID);
console.log(record.eventName);
console.log('DynamoDB Record: %j', record.dynamodb);
if(record.eventName == "INSERT"){
var connectionId = record.dynamodb.NewImage.connectionId.S;
try{
await send(connectionId, connectionId);
}catch(err){
log("Error", err);
}
log("sent");
}
}
return `Successfully processed ${event.Records.length} records.`;
};
I'm writing a lambda in node.js that will call an api(post) and gives back the resulting body and the code is as below.
const AWS = require('aws-sdk');
const request = require('request');
exports.handle = function(e, ctx, callback) {
var bodyDetails = {
uri: "myURL",
json: {
"requestChannel": "web1" },
"method": "POST"
};
callback = ctx.done;
var data = e.bodyJson || {};
request(bodyDetails, function(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(JSON.parse(JSON.stringify(body)));
jsonBody = JSON.parse(JSON.stringify(body));
console.log(body + "\t from suvccess") // Print the json response
callback(null, jsonBody); // Return the JSON object back to our API call
} else {
callback(error);
}
});
}
and I'm testing the same in my lambda console. by passing a blank json {} and I get back the correct response.
Now my next plan is to integrate this piece against API Gateway. So I've created an api for this in my apigateway and in that, I've created a resource named home. and in the home, I created a GET method. with the below details.
Integration type: Lambda Function
Use Lambda Proxy integration : checked
Lambda Region: us-east-1
Lambda Function: myWorkingLambdaName
when I tested this using the test option given by apigateway. I get the response as
Request: /home
Status: 502
Latency: 2942 ms
Response Body
{
"message": "Internal server error"
}
when I see my console I see the values of the success block printed, but the status code is 502. This is very confusing, please let me know where am I going wrong and how can I fix this.
Thanks
API Gateway expects the following properties to be returned from your Lambda:
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
So, instead of callback(null, jsonBody), you should be calling callback like this:
callback(null, {
isBase64Encoded: false,
statusCode: 200,
headers: {
"Access-Control-Allow-Origin" : "*",
},
body: JSON.stringify(jsonBody),
})