Lambda inconstant when querying my RDS database - javascript

When I go to test my code, the lambda does nothing, and at other times it runs my query and returns the data I have queried for. It's very inconsistent. It doesn't even give me an error. I am also using a proxy and that's not showing any errors. That's also not triggering.
I suspect it's something to do with the await/ async...
Here is my code:
async function RDSToken() {
vr signer = new AWS.RDS.Signer({
region: 'us-east-1',
hostname: 'proxy',
port: 3306,
username: 'username'
});
var host ='proxy'
var user ='username'
var db ='name'
let token = signer.getAuthToken({username: 'admin' });
let connectionConfig = {
host: host,
user: user,
database: db,
ssl: { rejectUnauthorized: false},
password: token,
authSwitchHandler: function ({pluginName, pluginData}, cb) {
console.log("Setting new auth handler.");
}
};
connectionConfig.authSwitchHandler = (data, cb) => {
if (data.pluginName === 'mysql_clear_password') {
let password = token + '\0';
let buffer = Buffer.from(password);
cb(null, password);
}};
try {
connection = await mysql2.createConnection(connectionConfig);
} catch(err) {
console.error('error connecting to the database');
console.error(err);
var response = {
statusCode: 500,
"headers": {
"Content-Type": "application/json"
},
body: 'error connecting to the database' +err
};
return response;
}
return connection
}
async function randomfact() {
var connection = await RDSToken();
let sql = 'SELECT * FROM quote_header;';
return await new Promise((resolve, reject) => {
connection.query(sql, (err, result) => {
if (err) {
reject(err);
}
else {
resolve(result);
}
});
});
}
async function Dashboard() {
const result = await randomfact();
console.log(result)
}

So I was correct there is something to do await/asnyc/promise.
Here is my updated code.
const connection = mysql2.createPool({
host: "host",
user: "admin",
password: "pw",
database : 'name',
waitForConnections: true,
connectionLimit: 3,
})
SelectAllElements = (connection) =>{
return new Promise((resolve, reject)=>{
connection.query('SELECT * FROM quote_header ', (error, elements)=>{
if(error){
return reject(error);
}
return resolve(elements);
});
});
};
async function Dashboard() {
try{
const result1 = await SelectAllElements(connection);
console.log(result1)
// here you can do something with the three results
} catch(error){
console.log(error)
}
}
But this works around 95% of the time. It doesn't like to work the first time I run the lambda but after then it works for a short time, then returns null again, then works again. I still dont understand what's causing it not to connect.

Related

Making a jest test file for mysql database calls

I'm very new to testing with Jest. I want to make a test to see if the following function returns user data from the database I have:
let dbConnect = require('../config/dbConnect');
let findUserByEmail = (email) => {
return new Promise(async (resolve, reject) => {
try {
dbConnect.query("SELECT * FROM user_login WHERE email = ?", email, function (error, results) {
if (error) reject(error);
let user = results[0];
if(user == undefined){
resolve()
}
resolve(user);
})
} catch (e) {
reject(e);
}
})
}
How would I go about making mock data to use in testing?
EDIT: Here is dbConnect:
let mysql = require('mysql');
let dotenv = require('dotenv');
dotenv.config({path: '../.env'});
let db = mysql.createConnection({
host: process.env.DATABASE_HOST,
database: process.env.DATABASE,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
});
db.connect(function (error) {
if (error) console.log(error);
else console.log("MYSQL Connected...");
});
module.exports = db;
Edit: fixed mistake
const mysql = require('mysql')
const mockQuery = jest.fn()
jest.mock('mysql', () => ({
createConnection: () => ({
connect: () => undefined,
query: mockQuery
}),
}))
describe('findUserByEmail', () => {
it('should resolve with the user when query suceeds', async () => {
mockQuery.mockImplementationOnce((sql, email, callback) => callback(null, ['TEST USER']));
expect(await findUserByEmail()).toBe('TEST USER');
})
});

AWS Lambda call 3 async functions by 1 Lambda call

Ok, i'm done. Please someone help me :(
I don't know how js and lambda works
What i have to do:
Send GET request and get response.
Write data from response to DynamoDb
I can do it 1by1 but can't do everything by 1 lambda call.
My code:
const https = require('https');
const crypto = require("crypto");
const AWS = require('aws-sdk');
const DynamoDb = new AWS.DynamoDB({region: 'eu-central-1'});
exports.handler = async (event) => {
let response;
console.log("Start");
let steamTicket;
let steamId;
if(event.body){
const body = JSON.parse(event.body);
if(body.steamticket && body.steamid){
steamTicket = body.steamticket;
steamId = body.steamid;
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'cant find steamid or steamticket in your request'
})
};
return response;
}
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'cant find request body'
})
};
return response;
}
await httprequest(steamTicket).then((data) =>{
if(data.response && data.response.params){
if(data.response.params.result == 'OK' && data.response.params.steamid == steamId){
console.log(JSON.stringify(data));
const sessionId = crypto.randomBytes(16).toString("hex");
console.log('Generated session id: ' + sessionId);
PutToDB(sessionId, steamId);
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'steam response is not OK or session != steamId'
})
};
return response;
}
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'invalid response from steam: ' + JSON.stringify(data)
})
};
return response;
}
});
};
async function PutToDB(sessionId, steamId){
var WriteParams = {
RequestItems:{
SteamSessions: []
}
};
WriteParams.RequestItems.SteamSessions.push({
PutRequest:{
Item: {
SteamId: {S: steamId},
SessionId: {S: sessionId},
ttl: {N: (Math.floor(Date.now() / 1000) + 600).toString()}
}
}
});
console.log('SessionIdToWrite: ' + sessionId);
return new Promise((resolve, reject) =>{
DynamoDb.batchWriteItem(WriteParams, function(err, data){
if(err){
console.log("Error", err);
}
else{
console.log("Success write", JSON.stringify(data));
}
})
})
}
async function httprequest(steamTicket) {
return new Promise((resolve, reject) => {
const options = {
host: 'partner.steam-api.com',
path: '/ISteamUserAuth/AuthenticateUserTicket/v1/?key=somekey&appid=someid&ticket=' + steamTicket,
port: 443,
method: 'GET'
};
const req = https.request(options, (res) => {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error('statusCode=' + res.statusCode));
}
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch(e) {
reject(e);
}
resolve(body);
});
});
req.on('error', (e) => {
reject(e.message);
});
// send the request
req.end();
});
}
I lost way already, i'm not even sure it should work like that.
And most confusing thing! This b give me this test results:
Run 1:
2021-03-05T13:28:47.741Z INFO Start
2021-03-05T13:28:48.612Z INFO {"response":{"params":{"result":"OK","steamid":"mysteamid","ownersteamid":"mysteamid","vacbanned":false,"publisherbanned":false}}}
2021-03-05T13:28:48.650Z INFO Generated session id: 6a5633a5f862d8663d0fe546a9c89feb
2021-03-05T13:28:48.650Z INFO SessionIdToWrite: 6a5633a5f862d8663d0fe546a9c89feb
DynamoDb is empty, here we can't see log from DynamoDb.batchWriteItem result.
Run 2:
2021-03-05T13:29:53.308Z INFO Start
2021-03-05T13:29:53.674Z INFO Success write {"UnprocessedItems":{}}
2021-03-05T13:29:54.048Z INFO {"response":{"params":{"result":"OK","steamid":"mysteamid","ownersteamid":"mysteamid","vacbanned":false,"publisherbanned":false}}}
2021-03-05T13:29:54.048Z INFO Generated session id: 05c62de782202fc100cea9d47e38242c
2021-03-05T13:29:54.048Z INFO SessionIdToWrite: 05c62de782202fc100cea9d47e38242c
And after second run i can see in DynamoDb sessionId from FIRST RUN (6a5633a5f862d8663d0fe546a9c89feb)
If i run it again, there will be id from 2nd run
I think it continues to run previous tasks on new run? Or what? I'm lost
Thank you for any help with it
You need to call reject / resolve in the DynamoDb.batchWriteItem call.
return new Promise((resolve, reject) =>{
DynamoDb.batchWriteItem(WriteParams, function(err, data){
if(err){
console.log("Error", err);
reject(err);
}
else{
console.log("Success write", JSON.stringify(data));
resolve();
}
})
})

What is the problem in the nodejs controller function?

exports.signupController = async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOne({ phone }).exec()
if (user) {
return res.status(400).json({
errorMessage: 'Phone Number already exists',
});
}
const newUser = new User();
newUser.phone = phone;
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
return res.status(200).json({
successMessage: 'Registration success. Please login',
});
} catch (err) {
console.log('signupController error: ', err);
res.status(500).json({
errorMessage: 'Server error',
});
}};
**I upload a node application in shared hosting! **
*But an error was showing in this controller function. All the time the catch block is running on the json. The error is unhandled promise rejection. *
signup(data)
.then((response) => {
console.log('Axios signup success: ', response);
setFormData({
phone: '',
password: '',
password2: '',
loading: false,
successMsg: response.data.successMessage,
});
history.push('/signin');
})
.catch((err) => {
console.log('Axios signup error: ', err);
setFormData({
...formData,
loading: false,
errorMsg: err.response.data.errorMessage,
});
});
this is react front end event handler
import axios from 'axios';
export const signup = async (data) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const response = await axios.post('/api/auth/signup', data, config);
return response;
};
the signup api function
Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function. for example:
const query = Band.findOne({name: "Guns N' Roses"});
assert.ok(!(query instanceof Promise));
// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function (doc) {
// use doc
});
// `.exec()` gives you a fully-fledged promise
const promise = query.exec();
assert.ok(promise instanceof Promise);
promise.then(function (doc) {
// use doc
});
If you are using exec() on your findOne query you should use:
exports.signupController = async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOne({ phone }).exec();
/// just a pseudo code
user.then('do your things').catch( 'log error')
const newUser = new User();
newUser.phone = phone;
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
return res.status(200).json({
successMessage: 'Registration success. Please login',
});
} catch (err) {
console.log('signupController error: ', err);
res.status(500).json({
errorMessage: 'Server error',
});
}};
for more details check this out: https://mongoosejs.com/docs/promises.html#should-you-use-exec-with-await?

User pool does not exist: AWS adminConfirmSignUp

For some reason, only the adminConfirmSignUp gives this error. Authentication using CognitoUser doesn't give this error. Both of them are configured to the same user pool and region.
Below is the code for authentication using cognitoUser, which is working:
public async login(req: UserLoginRequest): Promise<object> {
return new Promise<any>(async (resolve, reject) => {
console.log(`This is the req password-----> ${req.password}`)
try {
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
Username: req.emailAddress,
Password: req.password
});
var userData = {
Username: req.emailAddress,
Pool: this.userPool
};
this.cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
await this.authenticateUser(this.cognitoUser, authenticationDetails).then(value=> {
resolve(value)
}).catch(error => {
console.log(`This is the login error catch----> ${JSON.stringify(error)}`)
});
} catch (error) {
console.log(`I entered into catch .......${JSON.stringify(error)}`)
reject(error);
}
});
}
private async authenticateUser(cognitoUser: AmazonCognitoIdentity.CognitoUser, authenticationDetails: AmazonCognitoIdentity.AuthenticationDetails) {
console.log(`Inside authenticate user`);
console.log(`This is the cognitoUser -----> ${JSON.stringify(cognitoUser)} and these are the authentication details-----> ${JSON.stringify(authenticationDetails)}`)
try{
return new Promise<any>(async (resolve, reject) => {
await cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
console.log(`This is the success result ----> ${JSON.stringify(result)}`);
resolve(result)
},
onFailure: (error) => {
console.log(`This is the error being returned in onFailure ----> ${JSON.stringify(error)}`)
resolve(error)
}
})
})
}
catch(error){
rejects(error);
}
}
The confirm user, which uses AWS.CognitoIdentityServiceProvider doesn't work. Gives out an error user pool doesn't exist:
private async confirmUser(resetDetails: ResetPassword, cognitoAdmin: AWS.CognitoIdentityServiceProvider) {
console.log(`This is the admin config cognito ----> ${JSON.stringify(cognitoAdmin)}`)
return new Promise<any>(async (resolve,reject)=>{
console.log(`Inside confirm`);
const confirmParams = {
UserPoolId: process.env.COGNITO_USER_POOL_ID!,
Username: resetDetails.emailAddress!
}
console.log(`This is the user pool ID -----> ${confirmParams.UserPoolId} and this is the region----> ${cognitoAdmin.config.region}`);
await cognitoAdmin.adminConfirmSignUp(confirmParams, async (err, data) => {
if (err) {
console.log(`This is the admin user confirm error ---> ${err}`)
reject(err);
}
else {
cognitoAdmin.adminUpdateUserAttributes({
UserAttributes: [{
Name: 'email_verified',
Value: 'true'
}],
UserPoolId: process.env.COGNITO_USER_POOL_ID!,
Username: resetDetails.emailAddress!
}, (err, data) => {
if (err) {
reject(err)
}
else {
resolve(data)
}
}
)
}
})
})
}
This is the cognitoAdmin argument details sent to the cognitoAdmin parameter of the above confirmUser method:
var cognitoAdmin = new AWS.CognitoIdentityServiceProvider({ region: process.env.COGNITO_POOL_REGION!});

Javascript/ Node.js not waiting for sql query to come back with a response before it continues the code

I have a .js file that calls an external .js file that runs the following code:
const sql = require('../../node_modules/mysql');
module.exports =
{
connect_to_db: function (sql_query)
{
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err)=> {
if (err){
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
con.query(sql_query, (err, result) => {
if (err) throw err;
console.log('Data received from the DB');
console.log(result);
return result;
});
con.end((err) => {});
}
};
Which is run like:
const connect_to_DB = require('DB_Connection');
let sql_query = "SELECT * FROM table";
database_results.push(connect_to_DB.connect_to_db(sql_query));
console.log(database_results);
however this results in the code finishing before the sql query comes back with a result (data removed):
[ undefined ]
Connected to the DB!
Data received from the DB
[ RowDataPacket {
mail_id: ,
from: ,
to: ',
subject: ,
message: ,
date:,
read_date: } ]
Process finished with exit code 0
It looks like the push of the result is coming back as undefined as there is nothing to push at the point it does this. However I want it to wait until the response from the query comes back before it continues.
I was thinking of a promise perhaps but not sure if that would work something like:
const sql = require('../../node_modules/mysql');
module.exports =
{
connect_to_db: function (sql_query)
{
return new Promise((resolve, reject) => {
(async () => {
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err)=> {
if (err){
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
con.query(sql_query, (err, result) => {
if (err) throw err;
console.log('Data received from the DB');
console.log(result);
resolve();
return result;
});
con.end((err) => {});
})();
});
}
};
but when I run this I get this back:
[ Promise { <pending> } ]
I just need some help in order for the result to come back then the code to continue.
According to my view, The best possible way of solving this is by using callbacks in Node js.
Node js executes codes sychronously, let me explain by explaining what happened at your code
database_results.push(connect_to_DB.connect_to_db(sql_query));
console.log(database_results);
Here in your code console.log(database_results) is returned before executing the function connect_to_DB.connect_to_db(sql_query))
Your DBConnection.js can be modified as:
const sql = require('mysql');
exports.connect_to_db = function (sql_query, callback) {
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err) => {
if (err) {
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
con.query(sql_query, (err, result) => {
if (err) callback(err);
console.log('Data received from the DB');
console.log(result);
callback(result);
});
con.end((err) => { });
};
and the external js that calls the function connect_to_db function can be modified as:
'use strict';
const connect_to_DB = require('DB_Connection');
let sql_query = "SELECT * FROM table";
connect_to_DB.connect_to_db(sql_query, function (data, err) {
if (err) {
console.log(err);
}
else {
database_results.push(data);
}
});
console.log(database_results);
to know more about callbacks visit
You don't need to use promises and async/await in the same piece of code. Try something like this:
module.exports =
{
connect_to_db: async function (sql_query)
{
let con = sql.createConnection({
host: "localhost",
user: config.server_username,
password: config.server_password,
database: config.database_name
});
con.connect((err)=> {
if (err){
console.log("Problem connecting to the DB!");
return;
}
console.log("Connected to the DB!");
});
return await con.query(sql_query);
}
};
and then
const connect_to_DB = require('DB_Connection');
let sql_query = "SELECT * FROM table";
database_results.push(await connect_to_DB.connect_to_db(sql_query));
console.log(database_results);
Note that sice await keyword id only allowed inside async functions, this line database_results.push(await connect_to_DB.connect_to_db(sql_query)); should be inside an async function to work

Categories