Handling promise and async await function - javascript

I have this function in node and express
router.post('/', async (req, res) => {
const playlist = new Playlist({
song: req.body.song,
artist: req.body.artist
})
try {
const newPlaylist = await playlist.save()
res.status(201).json(newPlaylist)
} catch (err) {
res.status(400).json({ message: err.message })
}
})
However, I am getting this error
(node:23242) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'song' of undefined

I'd recommend you also wrap that first part in a try/catch. If req.body somehow doesn't get populated, or if new Playlist throws any sort of error, since this is an async function, that'll become a rejected Promise. This is safer:
router.post('/', async (req, res) => {
try {
const playlist = new Playlist({
song: req.body.song,
artist: req.body.artist
})
const newPlaylist = await playlist.save()
res.status(201).json(newPlaylist)
} catch (err) {
res.status(400).json({ message: err.message })
}
})
If you're getting a "Cannot read property 'song' of undefined" error, that means that the request body could not be parsed and remains undefined. Maybe the wrong content-type header was sent or you don't have a body parsing middleware set up correctly.

You have handled the exception using try ... catch and this is great.
Although outside of this try catch can be an issue.
So there might to be two errors here
Either req.body.song or req.body.artist OR Playlist is not a valid class
On your catch block res.status(400).json({ message: err.message }) this could be another issue.
It would be great if you try and catch entire code block and log the err and it would be clear.
UnhandledPromiseRejectionWarning is happened because you didn't catch the exception.

Related

POST request... UnhandledPromiseRejectionWarning: Unhandled promise rejection

When making a post request I get this error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection.
If somebody could explain why this is happening I would appreciate it :) Thanks
UPDATE
So, the this code POSTs successfully. But, when I uncomment the validation code I get that same error...
router.post("/", async (req, res) => {
//let client = validate(req.body);
//if (client.error) {
//res.status(400).json(result.error);
//return;
//}
let client = new Client(req.body);
try {
let savedClient = await client.save();
res.location(`/${savedClient._id}`).status(201).json(savedClient);
} catch (error) {
res.status(500).json(savedClient.error);
}
});
I don't see where you initialise savedClient and I think your error lies in your catch. You're referencing an object (savedClient) which doesn't appear to be in scope.
Try this:
router.post("/", async (req, res) => {
let client = new Client(req.body);
try {
let savedClient = await client.save();
res.location(`/${savedClient._id}`).status(201).json(savedClient);
} catch (error) {
console.log(error)
res.status(500).json(error);
}
});
maybe
let savedClient = await client.save();
I think it should be
...
} catch (error) {
res.status(500).json(savedClient.error);
}
because the promise's rejection error should be catch by the try/catch statement.

Error handling with deeply nested async functions

I'm having issues catching error when the functions are nested three levels deep. Here is a router with async functions:
router.post('/',
validatevalues,
async (req, res) => {
// if values are invalid then
// return res.status(422).send(errors.msg);
const result = await userController.post(req.body);
return res.status(201).send('Success');
},
);
const userController = {
async post(req) {
try {
await bcrypt.genSalt()
await bcrypt.hash();
await db.query(req.somevalues);
} catch (err) {
console.error(err);
};
};
};
const query = {
return new Promise(function(resolve, reject) {
...
if (err) {
reject(new Error(err));
} else {
resolve(res);
};
};
};
The console.error(err) is printing this stack trace
Error: error: duplicate key value violates unique constraint...
And then I get Uncaught AssertionError at the router level with Mocha testing:
Uncaught AssertionError: expected { Object (_events, _eventsCount, ...) } to have status code 422 but got 201
This seems expected since I am just console.error instead of throwing another newError at the controller level, but what do I need to do? If I throw another error, then wouldn't the stack trace be Error: error: error ...? This doesn't seem right to me.
You should only catch at the highest level:
router.post('/', validatevalues, async (req, res) => {
try {
const result = await userController.post(req.body);
return res.status(201).send('Success');
} catch(error) {
res.status(402).send(error.message);
}
});
If you still want to log at a lower level, you can rethrow the error:
} catch (err) {
console.error(err);
throw err;
} // no semicolon here, its unneccessary

Why is catch() block not running in Objection.js queries and instead then() always runs passing either 0 or 1 as a result?

So when running a query using Objection.js, the query will return data based on success or failure of said query and this data is passed to the then() block as a 0 or 1. Meaning to error handle, I'm having to check falsey values rather than send a response in the catch block. Am I doing something wrong?
const editIndustry = async (req, res, next) => {
const industry = await Industry.query().findById(req.params.industryId);
if (!industry) {
return res.status(404).json({
error: 'NotFoundError',
message: `industry not found`,
});
}
await industry
.$query()
.patch({ ...req.body })
.then(result => console.log(result, 'then() block'))
// never runs
.catch(err => {
console.log(err);
next(err);
});
};
App is listening on port 3000.
1 then() block ran
Your code is working as expected. The reason it's not going into the catch block is because there isn't an error. patch does not return the row. It returns the number of rows changed (see docs).
The function I think you're really looking for is patchAndFetchById (see docs). If you're concerned about generating a 404 error, you can append throwIfNotFound. Obviously, this will throw if it's not found in the database, which will let you catch. You can catch an instance of this error so you can send a proper 404 response. Otherwise, you want to return a 500. You'd need to require NotFoundError from objection.
const { NotFoundError } = require('objection');
const Industry = require('<myIndustryModelLocation>');
const editIndustry = (req, res) => {
try {
return Industry
.query()
.patchAndFetchById(req.params.industryId, { ...req.body })
.throwIfNotFound();
} catch (err) {
if(err instanceof NotFoundError) {
return res.status(404).json({
error: 'NotFoundError',
message: `industry not found`,
});
}
return res.status(500);
}
};

purposely throw error in a promise?

How to purposely make a promise fail? Sometime I just skip the test and assume everything is fine, but I want to purposely make the promise to fail so that my catch is working.
exports.submitJob = async (req, res, next) => {
const { cv } = req.body
const userId = req.user._id
try {
if(!cv) {
//how to pass error to catch block?
}
const save_submission = new Submission({
userId,
cv
}).save()
} catch(e => {
res.json({
status: 0,
error: e
})
})
next()
}
You can throw new Error('<your string here>');:
Note that catch is not something to be used with function syntax - the proper syntax is catch (e) { /* block that uses e */ }
const submitJobWhichWillFail = async (req, res, next) => {
const cv = null;
try {
if (!cv) {
throw new Error('cv must not be falsey!');
}
const save_submission = new Submission({
userId,
cv
}).save()
} catch (e) {
console.log('res.json with error ' + e);
}
}
submitJobWhichWillFail();
use the throw statement, maybe?
if(!cv) {throw("cv is absent");}
user-defined exception-types (alike one commonly has them in Java or PHP) are also possible and recommended, because one barely can differ the type by a string and otherwise can easily check the typeof the exception in the catch block. just learned from the MDN, that one eg. can also throw DOMException and Error.

Error handling node.js

I'm trying to learn node.js
I've got a working function and trying to handle an exeption like this:
Client.Session.create(device, storage, username, password)
.then(function(session) {
session.getAccount()
.then(function(account) {
console.log(account.params)
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(account.params));
return session
})
}).catch(Exceptions.AuthenticationError, function(err) {
console.log(err)
})
but it isn't working I'm still getting this in case of invalid login:
Unhandled rejection AuthenticationError: The username you entered doesn't appear to belong to an account. Please check your username and try again.
Try
Client.Session.create(device, storage, username, password)
.then(function(session) {
return session.getAccount() <-- NOTICE THE RETURN STATEMENT!!
.then(function(account) {
console.log(account.params)
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(account.params));
return session
})
}).catch(Exceptions.AuthenticationError, function(err) {
console.log(err)
})
Without the return, the .then handler of the promise returned by Client.Session.Create(...) will return a resolved promise (this is its default behaviour).
Promise rejections aren't any kind of exceiptions, so they aren't automatically rethrown as it would be if you were added, for example, something like this:
session.getAccount(...).then(...).catch(function(){throw "FooBar"});

Categories

Resources