Clean up AWS err response - javascript

I will preface this post with I am very new to JavaScript and even newer to AWS and their services.
I am currently working through this AWS tutorial and I am adapting it to fit my needs. I am not asking to make this work, as I already have it working for my needs.
In this bit of code
userPool.signUp('username', 'password', attributeList, null, function(err, result){
if (err) {
alert(err);
return;
}
cognitoUser = result.user;
console.log('user name is ' + cognitoUser.getUsername());
});
I am having trouble reformatting the err received by the function call when something goes wrong.
For example, I am using AWS Lambda to check the input validation for server side (using python), and I have it raise Exception("First Name is not long enough") which is what i get in return. However, when the alert(err) is called, correctly, I receive this:
UserLambdaValidationException: PreSignUp failed with error First Name is not long enough..
I have tried split on the err but the console says split is not a function of err.
So my question is, how can I strip this err and only get the message instead of the whole exception?
I have already tried err.split("error"); err.value; err.errorMessage; err["value"]; err["errorMessage"]; err.Error; and it doesn't work.
Also, when I console.log(err) I am presented with:
Error: First Name is not long enough..(...) //the (...) is the stacktrace

Related

How do I display my catch block message when there is no ID match?

I am getting data from an API and am displaying it on my local server.
Below is my code to get data which matches the ID from the API data:
router.get('/:id', async (req, res) => {
checkString(req.params.id)
try {
const person = await peopleData.getPersonById(req.params.id);
res.json(person);
} catch (e) {
res.status(404).json({ message: 'There is no person with that ID' });
}
If there is no match I want to display the message like in the catch block, but the code does not go there as not getting a match is not an error technically.
So I tried the below code to get this message:
router.get('/:id', async (req, res) => {
checkString(req.params.id)
try {
const person = await peopleData.getPersonById(req.params.id);
if(!person) res.json('There is no person with that ID'); // Added new line here
res.json(person);
} catch (e) {
res.status(404).json({ message: 'There is no person with that ID' });
}
This does the work but it prints the message with quotes around as a string, is there a way I can display the message in the catch block if no match is found?
You can throw an error and the catch will display it.
if(!person) throw new Error("There is no person with that ID");
....
then in the catch...
catch(e){
res.status(404).json({ message: e.message })
}
If you're sending people to a fullscreen "error stack" page, then you may not need to use res.json()! You can also use res.send()
if(!person){ res.send('<p>There is no person with that ID</p>'; return; }
// Or
if(!person){ res.send('There is no person with that ID'; return; }
You are returning Json responses, so it looks like your consumer is not a web page but another app. If so, you should return undefined or null if there is no person found, and let the web page or consumer decide what message to show. Reasons are:
It should be easier to modify web pages than code, and typically the UI or marketing people will always want to fine tune (usually many times) every message on a web page.
Your app is an API app. The place where the user not found message is to be shown can be many steps away. Or it may be inappropriate to show the message at all, for example the consuming app might want to redirect to/show a registration page instead if user is not found.
Your web site may be multi-lingual, and you don't want the back-end to be involved in this.
"User not found" in many situations is not really an error, but it all depends on your application.
The catch block in your case should be used to handle other errors, for example, your database server might be down, or the database request might have timed out, etc etc. Your current code will misleadingly show "user not found" if there is a database error!
I would also let the Express error handler take care of such real errors, instead of coding error handling for every API function you have:
router.get('/:id', async (req, res, next) => {
checkString(req.params.id);
try {
const person = await peopleData.getPersonById(req.params.id);
res.json(person); // assuming getPersonById returns null if user not found
} catch (e) {
next(e);
});
Your Express error handler, where the invocation of the above next function lands, should be something like this (asssuming router is your Express app):
router.use((err, req, res, next) => {
let statusCode = err.status || 500;
// Assuming your app need to return only json responses
res.json(err);
});

Error from nodejs server thrown not being passed back to AJAX

I have the following AJAX that will send the entered data to the node server and the controller will check whether such data exist in the database or not.
If I do enter the data correctly, then everything is working fine.
However, I tried enter anything that the database does not have and it immediately throw an error, causing the server to stop. The error said that I did not handle the event, so I tried with res.json(err) in the controller instead of throw new Error, hoping that the error will be passed back to AJAX under the error key, but it is still not working. The error still gets thrown and the node server terminate itself.
I would like the server to continue and alert to the user that the data that was entered is not in the database but I have no idea why my approach is not correct.
I was thinking of using this SO thread if I'm able to get the error message back first from server side.
jQuery Ajax error handling, show custom exception messages
To solve the server from stopping, I used the code in app.js that was referred from this link
How do I prevent node.js from crashing? try-catch doesn't work
I'm not sure whether should I use the accepted answer for my case.
function createProduct(inputval){
let inputAction = window.location.pathname;
$.ajax({
type: "POST",
url: inputAction,
data: {order: inputval.split('-')[0].trim(), lot: inputval.split('-')[1].substring(0,5)},
success: function(data) {
$('#product').val('');
//Another function to add HTML
display(data);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("XHR" + jqXHR)
console.log("Status" + textStatus)
console.log(errorThrown)
}
});
}
Controller File
exports.createProduct = function (req, res) {
db.Product.findOne({ "order": req.body.order, "lot": req.body.lot }).exec(function (err, product) {
if (!product || err){
throw new Error("The product entered returns null");
}
res.json(product);
});
};
Main File: app.js
process.on('uncaughtException', function (err) {
console.error(err);
console.log("Node NOT Exiting...");
});
You should use correct status code for your response. I suggest change your controller like below snippet
exports.createProduct = function (req, res) {
db.Product.findOne({ "order": req.body.order, "lot": req.body.lot }).exec(function (err, product) {
if (err){
res.status(500).end();//means internal server error
} else if (!product) {
res.status(404).end();//means product not found
} else {
res.json(product);
}
});
};
I finally figure it out thanks to feedback from other community, so I thought I would just share it here. It's so simple and silly me for neglecting such statement.
First, the code in app.js can just be removed.
Second, based on the answer given by #Milad Aghamohammadi. Instead of just:
res.status(500).end();
Use:
return res.status(500).json({err: "Server error"});
This way, the error is able to be handled by the AJAX error function and the node server will not be terminated from the event loop.

AWS Cognito Authentication Returns Error - Javascript SDK

I am using AWS Cognito to authenticate users in a new app that I am building.
I am using the amazon-cognito-identity-js library in my project (link to Github: https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js). Since users in this particular user pool cannot sign themselves up - I sign them up manually - I know that I need "Use case 23" as stated in the README.md from Github.
So my code is as follows:
...
const userPoolData = {
UserPoolId: <MY_USER_POOL_ID>,
ClientId: <MY_CLIENT_ID>
};
const userPool = new CognitoUserPool(userPoolData);
const authenticationData = {
Username: email,
Password: tempPassword
};
const userData = {
Username: email,
Pool: userPool
}
const authenticationDetails = new AuthenticationDetails(authenticationData);
const cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
console.log(result);
},
onFailure: (err) => {
console.log("Error from cognito auth: ", err);
},
newPasswordRequired: (userAttributes) => {
delete userAttributes.email_verified;
cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this);
}
})
...
When I execute this code, I successfully confirm my user. I can see this in the AWS Cognito console. However, instead of receiving the result object, I get an error in the javascript console on the client that says:
Uncaught (in promise) TypeError: Cannot read property 'onFailure' of undefined
at eval (CognitoUser.js:572)
at eval (Client.js:108)
But when I attempt to sign in with the newPassword in place of the tempPassword previously sent, I am now able to successfully get the resultobject with the three tokens all present.
So I know that everything is kinda working, but isn't what I am expecting.
What is causing this error? How can I fix it? I want to receive the result object immediately when the user first signs in with the tempPassword and their newPassword so that they can start using the app.
EDIT:
Thinking that I had to retrieve the userAttributes myself was a mistake. The newPasswordRequired function passes them automatically. So I updated my code above to go with "Use case 23" as presented on Github.
But now I get a slightly different error than before:
Uncaught (in promise) TypeError: callback.onFailure is not a function
at eval (CognitoUser.js:572)
at eval (Client.js:108)
Everything still works as far as Cognito is concerned, but there must be something wrong with my onFailure function, which is very strange.
Any thoughts?
Thanks in advance
Alright, I solved it. The issue was that I was using ES6 arrow functions. As Apolozeus pointed out, I needed to pass this into the cognitoUser.completeNewPasswordChallenge function. But due to the way ES6 behaves, this was returning undefined. So, changing my cognitoUser.authenticateUser function to the following solved everything:
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
resolve(result.getAccessToken().getJwtToken());
},
onFailure: function (err) {
console.log("Error from cognito promise: ", err);
reject(err);
},
newPasswordRequired: function (userAttributes) {
delete userAttributes.email_verified;
cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this);
}
})
I'm going to play around with the amazon-cognito-identity-js library a bit and see if I can get ES6 arrow functions to work here. It's really annoying to have to work around that.
Shout out to Apolozeus for the help
Please update the line cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes); into cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this) Basically, this will make sure the callback function within the same object.

AWS IOT createKeysAndCertificate gives network Failure ERROR

In the below code iot.listCertificates executes perfectly and i am able to see all certificates in AWS IOT console but when I try to execute command iot.createKeysAndCertificate it gives me NETWORK FAILURE ERROR.
Please help me with this,
Thank You!!
var params = {};
iot.listCertificates(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
alert("Attempting to create new thing!!");
params = {
setAsActive:false
};
iot.createKeysAndCertificate(params, function(err, data) {
if (err)
alert(err);
else
alert("New thing added to AWS IOT");
});
I just tried your code above from within a browser (Chrome 61) and it successfully listed the certificates and create new ones. So don't think the issue is with your code.
Maybe try ensuring the clock is correct on the machine your making the request from. I've see some AWS request fail due to the clock being off by a few minutes. They might also use the time in the request to generate the expiration date on the certificate.

Parse Cloud query error

I am trying to build a simple background job on the Parse Cloud. Right now, I'm just testing, but I am having a problem when performing a query.
If I comment out:
//query.ascending("createdAt");
the console log shows all the messages and no errors. If I don't comment it out, I get an error. Can anybody explain why this is happening? Is it an authentication error?
Parse.Cloud.job("cleanPosts", function(request, status) {
var Post = Parse.Object.extend("Post");
var query = new Parse.Query(Post);
query.ascending("createdAt");
query.each(function(post) {
console.log( "objectId:" + post.get("message") );
}).then(function() {
status.success("Success");
}, function(error) {
status.error();
});
});
When using Parse.Query.each, you do not need to (and cannot) provide an orderBy. It will run the callback for every object (actually ordered by objectId).
The official error is "Cannot iterate on a query with sort, skip, or limit." and it should appear if you log that in the error block.

Categories