CloudWatch Events trigger on Amazon Transcribe event - events

I'm working with the Amazon Transcribe service and trying to get CloudWatch Events to fire a Lambda function that executes a POST request to my API.
Here's the Lambda function
var querystring = require('querystring');
var http = require('http');
exports.handler = function(event, context) {
var post_data = querystring.stringify(
event
);
// An object of options to indicate where to post to
var post_options = {
host: '193e561e.ngrok.io',
port: '80',
path: '/api/lambda',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(post_data)
}
};
// Set up the request
var post_req = http.request(post_options, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log('Response: ' + chunk);
context.succeed();
});
res.on('error', function(e) {
console.log("Got error: " + e.message);
context.done(null, 'FAILURE');
});
});
// post the data
post_req.write(post_data);
post_req.end();
}
I've configured CloudWatch Events to listen to the Amazon Transcribe service and specifically for the status of a job changing to COMPLETED or FAILED.
What's surprising however is that there's no mention of the Transcribe job name in that event response.
Here's an example:
'version' => '0',
'id' => '1fa5cca6-413f-4a0f-0ba2-66efa49c247e',
'detail-type' => 'Transcribe Job State Change',
'source' => 'aws.transcribe',
'account' => '405723091079',
'time' => '2019-11-19T19:04:25Z',
'region' => 'eu-west-1',
'detail' => NULL,
This is the only way I can think of my app working where the transcription job is invoked via the Amazon Transcribe service and then when it's done, hit my API to update the necessary models in my app but without getting the Transcribe job name, it won't work.
Any advice appreciated.

Per your updated question, I suspect your issue is actually here:
var post_data = querystring.stringify(
event
);
Querystring does not support nested objects, such as the detail block of the cloudwatch event. More info:
https://github.com/sindresorhus/query-string#user-content-nesting
So although you didn't indicate it in your question, I suspect you are showing the response that you are receiving as the result of this lambda post, not the raw response/event you are receiving from AWS Transcribe.
Perhaps instead of querystring:
var post_data = JSON.stringify(event);

Related

Serverless Cloudwatch events appearing encrypted

I'm testing out Cloudwatch logs as a trigger for serverless functions. However when my serverless function is triggered, it's just outputting jibberish, which I figured was some form of encryption. Unfortunately I don't know what that encryption is.
Here's the output:
{"awslogs":{"data":"H4sIAAAAAAAAAGVR...4BmF05wEAAA=="}}
And here's the function's code:
const handler = async (event) => {
console.log('*********RECEIVED EVENT FROM CLOUDWATCH**********')
console.log(JSON.stringify(event));
return {
statusCode: 200,
body: JSON.stringify(
event,
null,
2
)
}
};
export { handler };
The "data" section that you get back is base64 encoded and compressed. To get the information out from the event, you just need to decode the base64 information and unzip the data.
Here's a code snippet that shows basically what needs to be done in order to read the log data.
...
const payload = Buffer.from(event.awslogs.data, 'base64');
zlib.gunzip(payload, (err, res) => {
if (err) {
...
}
const parsed = JSON.parse(res.toString('utf8'));
...
});

How to send message back to device from Lambda function?

Is there any way we can send a message to a device from Lambda function which is invoked by Alexa Skill. The message contains some values collected by Lambda function.
So basically I want to do this:
Device ---> Voice command ---> Alexa Skill --(Trigger)--> Lambda function
Lambda function(collect values) ---- message ---> Device
Is there any example in Java?
Thanks for any pointer/help.
-James
Invoke Alexa device from lambda function is a very similar question, with the answer: "it's not possible YET"
I will elaborate. You can send notifications to all users of a skill such as a new feature, however, you cannot send a notification to a specific user that invokes a function.
To send notifications to all users of an Alexa skill who have notifications enabled, see this design.
Reference this thread for more information on the limitations of sending a notification to a specific user.
What you are asking can be done.
First the voice command does not come from a human from your diagram.
A device talks to Alexa. Alexa invokes or triggers Lambda. Lambda function messages device.
The function inside Lambda is http or https. If your device can handle https or TLS encryption then good. But most of the device are small and have limited computing power, so you will end up using http. As of now 2020, AWS allows http, but a year from now it requires you to use https or TLS 1.3 due to federal regulations. But we don't know until it happens.
Below is a sample of Lambda http post in NodeJS. The trigger data comes in request. So you should know what JSON will come in and extract your data from JSON using the if statement.
NodeJS website has good examples for http.
Now your device is the server. It has to anticipate the Lambda request and process it and reply to Lambda if needed.
Now your device talks and receives information.
const http = require('http');
exports.handler = async (request, context) => {
if (request.directive.header.namespace === 'FromAlexaSkill') {
httpost("This is your data to device", "192.168.1.2");
}
//**********************************************
let httpPost =async (postData, servername) => {
let dataString = '';
const response = await new Promise((resolve, reject) => {
const options = {
hostname: servername,
port: 1777,
path: '/dim',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) =>
{
res.setEncoding('utf8');
res.on('data', chunk => {
dataString += chunk;
});
res.on('end', () => {
resolve({
"body":dataString
});
});
});//http.request
req.on('error', (e) => {
console.error("problem with request: "+e.message);
reject({
statusCode: 500,
body: 'Something went wrong!'
});
});
// Write data to request body
req.write(postData);
req.end();
}); //Promise
return response;
};//httpPost
}

CloudWatch log multiple custom metric filters to trigger lambda function

I just start learning on aws, and I have created couple of cloudwatch log custom metric filter and subscribe to the same lambda function do to some stuff, but I want to get my lambda function to perform difference action depends on which metric filter trigger it. In the lambda function(in python) how can I know which metric filter trigger it?
In Lambda function handlers, you'll have an event object, this object will usually contain information about the request. According to the documentation, this is base64 encoded and zipped. I imagine this is because the logs are expected to get fairly large.
Once unzipped the structure is:
{ messageType: 'DATA_MESSAGE',
owner: '123456789123',
logGroup: 'testLogGroup',
logStream: 'testLogStream',
subscriptionFilters: [ 'testFilter' ],
logEvents:
[ { id: 'eventId1',
timestamp: 1440442987000,
message: '[ERROR] First test message' },
{ id: 'eventId2',
timestamp: 1440442987001,
message: '[ERROR] Second test message' } ] }
This can be found in the AWS docs under CloudWatch Logs.
You can check on the subscriptionFilters field in the event data to check which filter triggered the Lambda.
If your Lambda was in NodeJS, you could write something like the following:
const zlib = require('zlib');
const YOUR_FILTER = 'filter1';
exports.handler = async (event) => {
const zippedInput = new Buffer(event.awslogs.data, 'base64');
await new Promise((resolve, reject) => {
zlib.gunzip(zippedInput, function (e, buffer) {
const awslogsData = JSON.parse(buffer.toString('utf-8'));
// Conditions on filters to do something
if (awslogsData.subscriptionFilters.includes(YOUR_FILTER)) {
// do something
} else if (awslogsData.subscriptionFilters.includes('your_other_filter')) {
// do something else
}
resolve();
});
})
return 'Hello from Lambda!'
};

Redirect link to distribution slack app

I'm trying to redirect URL to distribute (OAuth 2.0)my slack app with API gateway and lambda function (AWS) but I can't realize how to get the code.
the event that returns is null.
My lambda code :
// Lambda handler
exports.handler = (event, context, callback) => {
var messageTest = {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
code: event.code
};
var queryTest = qs.stringify(messageTest);
https.get(`https://slack.com/api/oauth.access?${queryTest}`, (res, err) => {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
});
res.on('end', function() {
var result = JSON.parse(data.join(''))
console.log(result);
});
});
callback(null);
};
My redirect URL is the lambda URL.
The event that i get is null.
How can i get the "code" from the oAuth 2.0?
Assuming you are using Lambda Proxy integration (and therefore you don't use a Body Mapping Template), the JSON payload that you send to your API Gateway will be received by your Lambda as a stringified JSON in event.body.
So, you'll need to parse that first and you can get your code.
const body = JSON.parse(event.body)
const code = body.code
Reference: Input Format of a Lambda Function for Proxy Integration

Difficulty creating a functional Angular2 post

I'm trying to send a post request to another service (a Spring application), an authentication, but I'm having trouble constructing a functional Angular2 post request at all. I'm using this video for reference, which is pretty new, so I assume the information still valid. I'm also able to execute a get request with no problems.
Here's my post request:
export class LogIn {
authUser: string;
authPass: string;
token: any;
constructor(private _http:Http){}
onSubmit() {
var header = new Headers()
var json = JSON.stringify({ user: this.authUser, password: this.authPass })
var params2 = 'user=' + this.authUser + '&password=' + this.authPass
var params = "json=" + json
header.append('Content-Type', 'application/x-www-form-urlencoded')
this._http.post("http://validate.jsontest.com", params, {
headers: header
}).map(res => res.json())
.subscribe(
data => this.token = JSON.stringify(data),
err => console.error(err),
() => console.log('done')
);
console.log(this.token);
}
}
The info is being correctly taken from a form, I tested it a couple of times to make sure. I am also using two different ways to build the json (params and params2). When I try to send the request to http://validate.jsontest.com, the console prints undefined where this.token should be. When I try to send the request to the Spring application, I get an error on that side:
Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
Does anyone know what I'm doing wrong?
In fact you need to use the GET method to do that:
var json = JSON.stringify({
user: this.authUser, password: this.authPass
});
var params = new URLSearchParams();
params.set('json', json);
this._http.get("http://validate.jsontest.com", {
search: params
}).map(res => res.json());
See this plunkr: http://plnkr.co/edit/fAHPp49vFZJ8OuPC1043?p=preview.

Resources