context.awsRequestId from lambda - node.js

Is the uuid from context.awsRequestId really unique? I want to use it in association with the creation of a resource, so I can now when the resource was created:
const uuid = require('uuid');
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.create = (event, context, callback) => {
const timestamp = new Date().getTime();
const data = JSON.parse(event.body);
if (typeof data.text !== 'string') {
console.error('Validation Failed');
callback(null, {
statusCode: 400,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t create the todo item.',
});
return;
}
const params = {
TableName: process.env.DYNAMODB_TABLE,
Item: {
id: context.awsRequestId,
text: data.text,
checked: false,
createdAt: timestamp,
updatedAt: timestamp,
},
};
// write the todo to the database
dynamoDb.put(params, (error) => {
// handle potential errors
if (error) {
console.error(error);
callback(null, {
statusCode: error.statusCode || 501,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t create the todo item.',
});
return;
}
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(params.Item),
};
callback(null, response);
});
};
Thank you.

I don't think this is clearly documented, but based on observations, these UUIDs do not appear to be randomly generated (which is good for uniqueness). Instead, they look like they are a variant of Type 1 UUIDs, where most of the bytes actually represent a timestamp, so it would appear to be a safe assumption that they are both spatially and temporally unique.
When the digit M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx is set to 1, the UUID should be a Type 1 and should represent a high resolution timestamp and "node" identifier, although in this case the node component seems to carry no meaningful information... but the timestamps seem close to real time (though not precisely so).

Related

Api to accept written number as option?

I have using azcapture api which only accepts number as id at the end of 'path' Options of Fetch/Request api and works when I type in the id e.g.
Var options = {
'path':'url+key+1234455
}
When 1234455 is typed like above it works. But since this is the resp I cannot beforehand know the id so I pass it from the req result which was a POST and now I do a GET, effectively I have chained them without using Promises:
Function secondCall(id)
Console.log (id)
Var options = { 'path': url+key+id
}
This above always fails even if I parse id with parseInt or Number () or if I parse or coerce then
id.toString()
since ClientRequestArgs.path is a string (ClientRequestArgs.path?: string), I believe, it always resolves to a string.
Am I seeing double here or is there a fundamental issue?
POSTMAN works fine btw and the code I have below is exported from POSTMAN except in chainResolve function the first 4 lines are my conversion code.
If I change this line and replace the resolvedID to a pre generated id it will work:
url: 'http://azcaptcha.com/res.php?key=kowg1cjodmtlyiyqheuzjfzta4ki0vwn&action=get&id=335439890',
But as resolvedID the converted string (pre generated id) into an int it won't work.
Full code with keys omitted:
var request = require('request');
var fs = require('fs');
var http = require('follow-redirects').http;
var axios = require('axios');
var options = {
'method': 'POST',
'url': 'http://azcaptcha.com/in.php?key=key&method=post',
'headers': {
},
formData: {
'file': {
'value': fs.createReadStream('C:/Users/jsonX/Documents/fiverr/captchatest.png'),
'options': {
'filename': 'C:/Users/jsonX/Documents/fiverr/captchatest.png',
'contentType': null
}
}
}
};
//let respondedID;
convertToInt = (x) => {
var converted=parseInt(x[1], 10);
return converted;
}
request(options, function (error, response) {
if (error) throw new Error(error);
var respondedID = response.body;
console.log('line 26 '+respondedID);
chainResolve(respondedID);
});
chainResolve = (id) => {
var sid = id.split('|');
var resolvedID=parseInt(sid[1], 10)
console.log(parseInt(sid[1], 10));
console.log('line 40 '+convertToInt(sid));
var config = {
method: 'get',
url: 'http://azcaptcha.com/res.php?key=key&action=get&id=resolvedID',
headers: { }
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
Solved it! It turns out this API will not give you back any result if the resp is CAPTCHA_NOT_READY. So the solution was to set a timeout and push this with a callback in my response block of the second request:
axios(config)
.then(function (response) {
if (result === 'CAPCHA_NOT_READY'){
console.log('Captcha is being processed');
var startTime = setTimeout(function() {
waitR(id);
clearTimeout(startTime);
},5000);
} else {
console.log(result.split('|')[1]);
}
})
.catch(function (error) {
console.log(error);
});
waitR = (id) => {
console.log('The result is being processed ...');
chainResolve(id);
}

Deleting a row if the value is a duplicate DynamoDB

I'm trying to compare if dynambodb has duplicate phoneNumbers and if it does I want to delete the older one. There doesn't seem to be a whole lot, on doing this through lambda. Some help would be appreciated. Thanks
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: process.env.DYNAMODB_TABLE,
ProjectionExpression: "phoneNumber, createdAt",
};
module.exports.list = (event, context, callback) => {
// fetch all LakeSubscriptions from the database
dynamoDb.scan(params, (error, result) => {
// handle potential errors
if (error) {
console.error(error);
callback(null, {
statusCode: error.statusCode || 501,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t fetch the item.',
});
return;
}
/*
for(item in result.phoneNumber){ //not really sure how I can pull these individual values I need to use to compare.
module.exports.delete = (event, context, callback) => {
const params = {
TableName: process.env.DYNAMODB_TABLE,
Key: {
id: event.pathParameters.id,
},
};
// delete the lakeSubscription from the database
dynamoDb.delete(params, (error) => {
// handle potential errors
if (error) {
//error handling
});
return;
}
});
};
}
*/
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(result.Items),
};
callback(null, response);
});
};
Not a expert in Node.JS , but some suggestions
Scan operation results are returned in pages of 1 MB each, So the above code will not return all the rows in the dynamodb . Refer to the Step 4.3: Scan of this documentation
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.NodeJs.04.html
This would give you some idea on how to paginate and get all records from dynamodb . you can add all the results
Also refer the following post
How to fetch/scan all items from `AWS dynamodb` using node.js
This should give u a better idea

Node JS serverless rest API lambda function that first performs GET request and then POST if condition is met

I'm new to NodeJS and I'm supposed to write a serverless rest API for a online store (school project). The team I'm in is responsible of the orders customers place. To be able to place the order there has to be enough quantity in inventory (another API), so we need to check quantity in inventory using GET before we store the order in a database using POST. How should we go about this? This is what I have tried, but I end up getting timeout. The code below is based on this example: aws-node-rest-api-with-dynamodb for me to get the hang of NodeJS and serverless.
.yml file
functions:
create:
handler: todos/test.f
events:
- http:
path: todos
method: post
cors: true
test.js
const create = require("./create.js");
exports.f = function() {
const https = require('https');
https.get('url goes here', (resp) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log(data);
var str = String(data);
console.log("Check: " + (str.trim() == "OK"))
create.c(); //also tried create.create();
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
}
create.js
'use strict';
const uuid = require('uuid');
const dynamodb = require('./dynamodb');
exports.c = function (){
console.log("Fire!");
}
module.exports.create = (event, context, callback) => {
const timestamp = new Date().getTime();
const data = JSON.parse(event.body);
if (typeof data.text !== 'string') {
console.error('Validation Failed');
callback(null, {
statusCode: 400,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t create the todo item.',
});
return;
}
const params = {
TableName: 'todos',
Item: {
id: uuid.v1(),
text: data.text,
checked: false,
createdAt: timestamp,
updatedAt: timestamp,
},
};
// write the todo to the database
dynamodb.put(params, (error) => {
// handle potential errors
if (error) {
console.error(error);
callback(null, {
statusCode: error.statusCode || 501,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t create the todo item.',
});
return;
}
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(params.Item),
};
callback(null, response);
});
};
Any thoughts on how to get this to work?

Lambda always returns 200

When I provide my Lambda function with an invalid primary key for a GetItem call, it seems to search for that key until it times out, but then it still just returns a 200 (without a response body).
Is there any way to make sure the function aborts once it has gone through the table once without finding the key and returning an error message instead? Seems like a waste of function time to have it look over and over again until it times out? Furthermore, it times out after 1000ms which is not my function timeout setting which makes me think that there is something else going on here than a regular timeout.
Code:
'use strict';
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {
const done = (err, res) => {
const response = {
statusCode: err ? '400' : '200',
body: err ? JSON.stringify(err) : JSON.stringify(res)
}
callback(null, response);
};
const groupId = event.pathParameters.groupId;
const eventId = event.pathParameters.eventId;
docClient.get({
TableName: 'events',
Key: {
groupId,
eventId
}
},
(err, data) => {
done(err, data.Item);
});
};
In a perfect world, I would like for the function to stop once it has "realized" that I have supplied an incorrect primary key and then return some error that would tell the client that it could not find an item in the table with that primary key, yes!
This can only happen if we let the DB operation do it! SO we have to be dependent on the response from the DB.
Here's what we can do: Based on response return the error whether 200 or 400!
To check if the res isEmpty method of Lodash and return 400 using your done function.
'use strict';
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
const { isEmpty } = require('lodash');
exports.handler = (event, context, callback) => {
const done = (err, res) => {
const response = {
statusCode: (err || isEmpty(res)) ? '400' : '200',
body: err ? JSON.stringify(err) : JSON.stringify(res)
}
callback(null, response);
};
const groupId = event.pathParameters.groupId;
const eventId = event.pathParameters.eventId;
docClient.get({
TableName: 'events',
Key: {
groupId,
eventId
}
},
(err, data) => {
done(err, data.Item);
});
};
Hope this solves your query!

Cant insert data into DynamoDB using new nodejs 8.10

I want to use new nodejs 8.10 for developing my lambdas. A simple piece of code when written in node 6.10 style works but the same(similar) code doesn't work when I use node 8.10.
Below is working code which successfully inserts data into dynamodb table(nodejs 6.10)
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: 'us-east-1'});
var documentClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
exports.handler = (event, context, callback) => {
// TODO implement
var params = {
Item: {
client: 'client_'+Math.random(),
Type: 1,
Status: true,
json: { foo: 'bar', address:{ city:'Pune', street: 'ABC Nagar', pin:'411099'} }
},
TableName: 'clients'
};
documentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
callback(err, null);
} else {
console.log("Success", data);
// return "Hi, insert data completed";
callback(null, data);
}
});
};
And below one which is node 8.10 style which doesn't work(means doesn't insert data into dynamodb table). I keep getting null as return value.
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: 'us-east-1'});
var documentClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
exports.handler = async (event) => {
// TODO implement
var params = {
Item: {
client: 'client_'+Math.random(),
Type: 1,
Status: true,
json: { foo: 'bar', address:{ city:'Pune', street: 'ABC Nagar', pin:'411099'} }
},
TableName: 'clients'
};
documentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data);
return "Hi, insert data completed";
}
});
};
I spent searching 2-3 hours searching.. couldn't find any article or any question similar. Can anyone tell me what am I doing wrong?
Async / Await is a syntactical sugar for promise, Your documentClient.put should be wraped with promise. Since documentClient.put is based on callback appoach, you have to wrap it with promise
var AWS = require('aws-sdk');
// Set the region
AWS.config.update({region: 'us-east-1'});
var documentClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
exports.handler = async (event) => {
// TODO implement
var params = {
Item: {
client: 'client_'+Math.random(),
Type: 1,
Status: true,
json: { foo: 'bar', address:{ city:'Pune', street: 'ABC Nagar', pin:'411099'} }
},
TableName: 'clients'
};
let putItem = new Promise((res, rej) => {
documentClient.put(params, function(err, data) {
if (err) {
console.log("Error", err);
rej(err);
} else {
console.log("Success", data);
res("Hi, insert data completed");
}
});
});
const result = await putItem;
console.log(result);
return result
};
Note: Its advisable to use DB operations in separate file,rather than using in handler function itself
Did you look in your table to see if it's inserting data? I think it is.
The problem with your async-style code is that you aren't returning a value. Returning "Hi, insert data completed" from the put callback doesn't return a value from handler.
You could manually create a promise and return that from handler, but I'd try using promisify.
This code is untested but should be close:
...
const util = require('util');
...
documentClient.putPromise = util.promisify(documentClient.put);
...
try {
const data = await documentClient.putPromise(params);
console.log("Success", data);
return "Hi, insert data completed";
}
catch (err) {
console.log("Error", err);
}
Here's more on promisify: http://2ality.com/2017/05/util-promisify.html
Calling await dynamo.put(params).promise(); is how I solved this issue after some googling. Specifically, it seems like calling foo.promise(); in the aws sdk is supported now.

Resources