How to reformat a Javascript Try/Catch to a then/catch - javascript

The following code is anAPI endpoint taking a URL of an image as input, and outputing the URL of the newly created thumbnail.
I am trying the refactor the try/catch, to a .then().catch(), as I intend to had more then()s, to upload the newly created thumbnail to AWS s3 for instance).
const express = require("express");
const jimp = require('jimp');
const { v1: uuidv1 } = require('uuid');
const router = express.Router();
// GET all data from watchlist
router.post("/", async (req, res) => {
const url = req.body.url;
const tempPath = './public/uploads/';
const tempFileName = uuidv1();
const tempURL = tempPath + tempFileName;
const cleanedUrl = tempURL.slice(2, tempURL.length);
try {
jimp.read(url, (err, img) => {
img.resize(120, 120)
.quality(60)
.write(tempURL)
})
res.status(201).json({ thumbUrl: `http://localhost:5000/${cleanedUrl}` });
} catch (err) {
res.status(400).json({
error: `${err})`,
});
}
});
module.exports = router;
The code I had in mind to remplace the Try/Catch, seems not to be working, as when using it, the API freezes and deliver no response (and no errors!?).
jimp.read(url, (err, img) => {
img.resize(120, 120)
.quality(60)
.write(tempURL)
})
.then(() => {
res.status(400).json({
thumbUrl: `http://localhost:5000/${cleanedUrl}`,
});
})
.catch((err) => {
res.status(400).json({ error: `${err}` })
})
If someone could point me the error (or some good ressources for dummy about how to use then/catch, I can't find any I understand online) I will be highly grateful!

The Promise based version of .read does not accept a callback, so the code in the callback is getting ignored. You also have a typo - the status(400) in the Promise-based version in the .then should be .status(201). Change to:
jimp.read(url)
.then((img) => {
img.resize(120, 120)
.quality(60)
.write(tempURL);
res.status(201).json({
thumbUrl: `http://localhost:5000/${cleanedUrl}`,
});
})
.catch((err) => {
res.status(400).json({ error: `${err}` })
})
As a side note, whenever you're using Node-style callbacks, identify errors by checking the first error parameter - in your original code, you're ignoring it (and the surrounding try/catch isn't accomplishing anything). For example:
jimp.read(url, (err, img) => {
if (err) {
res.status(400).json({
error: `${err})`,
});
return;
}
img.resize(120, 120)
.quality(60)
.write(tempURL);
res.status(201).json({ thumbUrl: `http://localhost:5000/${cleanedUrl}` });
});

Related

Can't get result from a nodejs module

I wrote a small Javascript module to get rows from a MongoDB database:
async function getAll() {
await mongoose.connect(config.mongoURL).catch(err => { console.log(err); });
const conn = mongoose.connection;
conn.collection('healthdata')
.find({}).toArray().then(result => {
console.log('=>Docs:', result);
return result;
}).catch (err => {
console.log(err);
}).finally(() => {
conn.close();
});
}
exports.getAll = getAll
I get the correct display from the console ("=>Docs:").
But, when I want to get the result from the following calling function, I get the Undefined value ("Result:"):
app.get("/", async (req, res) => {
var docs = await db.getAll().then();
console.log("Result:", docs);
res.render("index.html");
});
What is missing? Wrong?
you should not mix promises with async/await, so either the answer provide by G-Force but remove the await before db.getAll() or use var docs = await db.getAll(); this should solve your problem.
Bro if you are using mongoose follow these to get data from mongoose schema
schema.find().exec().then(result=>{
console.log(result)
}).catch(error=>{
console.log(error)
})
here all schema data in result that we console if any error come it displays in console.log(error)
I think the console.log(Result:...) line is executing before your getAll completes.
I would wrap it inside the "then" clause:
app.get("/", async (req, res) => {
const docsReturned = await db.getAll()
.then(docs => {
console.log("Result:", docs);
res.render("index.html");
})
.catch(err => {
console.error(err);
}));
return(docsReturned);
I also suggest adding a catch for any errors...good practices. :)

How to return some data from a function nested in another, using Async and Await? [duplicate]

This question already has answers here:
Why is my asynchronous function returning Promise { <pending> } instead of a value?
(9 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I have the following piece of code: an endpoint getting the URL of an image, downloading it, resize it, saving it locally, then uploading it to a S3 bucket. Every piece of code works fine on it's own.
// Post a URL of a pic and get a URL of its thumb on AWS S3
router.post("/", (req, res) => {
const url = req.body.url;
const tempPath = './public/uploads/';
const tempFileName = uuidv1();
const createThumbPic = async () => {
const tempURL = tempPath + tempFileName;
jimp.read(url, async (err, img) => {
if (err) {
res.status(400).json({
error: `${err})`,
});
return;
}
img.resize(120, 120)
.quality(60)
.write(tempURL);
});
return tempURL;
}
const uploadThumbnailToS3 = async () => {
const tempURLThumb = await createThumbPic();
const file = await fs.readFileSync(tempURLThumb);
const params = {
Bucket: process.env.S3_BUCKET_ID,
Key: tempFileName,
Body: file
};
// Uploading files to the bucket
const fileUrlOns3 = await s3.upload(params, function (err, data) {
if (err) {
res.status(400).json({ error: err });
}
res.status(201).json({ thumbUrl: resData });
return data.Location;
});
return fileUrlOns3;
}
// Execute Code and respond to client
uploadThumbnailToS3().catch((err) => {
res.status(400).json({ error: err });
});
});
the Error I am getting back from this endpoint:
{
"error": {
"errno": -2,
"syscall": "open",
"code": "ENOENT",
"path": "./public/uploads/imagefiletemp.jpg"
}
}
The problem comes from the follwing to lines: It seems that fs.readFileSyncruns before that createThumbPic() is totally finished. Hence that the readFileSync doesn't find the file it should read, and throw that error back.
const tempURLThumb = await createThumbPic();
const file = await fs.readFileSync(tempURLThumb);
Somehow I know that createThumbPic return tempURLThumb before that the fiel is finished, as I get the response in postman, than 1 sec later I see the file appearing in my directory.
const createThumbPic = async () => {
const tempURL = tempPath + tempFileName;
jimp.read(url, async (err, img) => {
if (err) {
res.status(400).json({
error: `${err})`,
});
return;
}
img.resize(120, 120)
.quality(60)
.write(tempURL);
});
return tempURL;
}
How to make createThumbPicwait until img.resize is completely finished before returning tempURL?
I tried my best learning ASYNC/AWAIT, and thought I had figured, but it seems like something is still off in my code. Any tip?
You need to await your promise:
// upload to S3
const thumbOnS3 = await uploadFileS3(tempURL, tempFileName);
console.log(thumbOnS3)

THEN statement returning with promise/always return and consistent-return bugs

This is the code for a google cloud function I am trying to deploy. I'm getting a error saying that my .then() promises or inconsistent. Does anyone know what I am doing wrong?
const admin = require('firebase-admin');
const twilio = require('./twilio');
module.exports = function(req, res) {
if (!req.body.phone) {
return res
.status(422)
.send({ error: 'You must provide a phone number' });
}
const phone = String(req.body.phone).replace(/[^\d]/g, '');
admin
.auth()
.getUser(phone)
.then(userRecord => {
const code = Math.floor((Math.random() * 8999 + 1000));
const message = {
body: 'Your code is ' + code,
to: phone,
from: '+18053167032'
};
const callback = (err) => {
if (err) {
return res.status(422).send(err);
}
admin
.database()
.ref('users/' + phone)
.update(
{ code: code, codeValid: true },
() => { res.send({ success: true }
);
};
twilio.messages.create(message, callback);
})
.catch((err) => {
res.status(422).send({ error: err });
});
}
Off the top of my head, it is hard your indentation blocks using the curly braces exactly, and in response to #hanoldaa's mention of arrow functions, it is quite important to be able to trace exactly where the userRecord => function will end. If it says your .then promises are inconsistent, then I would assume you are either calling .then on non-promise objects, or you are not handling unresolved Promises.
Javascript.info has a great suggestion on a global handling of unresolved promises, using:
window.addEventListener('unhandledrejection', function(event) {
// the event object has two special properties:
alert(event.promise); // [object Promise] - the promise that generated the error
alert(event.reason); // Error: Whoops! - the unhandled error object
});
new Promise(function() {
throw new Error("Whoops!");
}); // no catch to handle the error
Hope this helps!
At the end, you do
.catch((err) => {
res.status(422).send({ error: err });
});
but err shouldn't be wrapped in parenthesis. Use
.catch(err => {
res.status(422).send({ error: err });
});

Axios code not running after `.then`

I am new to react/nodejs/express/javascript and have encountered the following problem:
I want to get a number, then post that number + 1, then I want to create a new js object using that number(newFreshId) and I want to add it to add that event to my schedulerData. When I try running the code, I can get and post to /api/num, but I everything after the .then(function(response) { doesnt appear to run.
I wanted to do this sequentially, so I used .then after every task so that I would not have encountered a problem.
I also tried to remove all the .thens in favor of a while loop that waits for the value to change. This also did not work.
CODE:
CLIENT:
this.newEvent = (schedulerData, slotId, slotName, start, end, type, item) => {
let newFreshId = 0;
let newEvent = {}
axios.get("/api/num").then(function(response) {
newFreshId = response.data[0] + 1;
// console.log(newFreshId);
}).then(function() {
axios.post("/api/num", {
id: newFreshId
}).then(function(response) {
console.log(response)
// handle success
newEvent = {
id: newFreshId,
title: this.state.title,
start: start,
end: end,
resourceId: slotId
};
schedulerData.addEvent(newEvent);
this.setState({
viewModel: schedulerData
});
// while(JSON.stringify(newEvent) === '{}'){
// console.log('waiting')
// }
console.log(newEvent)
schedulerData.addEvent(newEvent);
console.log(newEvent)
this.setState({
viewModel: schedulerData
});
})
})
};
SERVER:
app.get('/api/num', function(req, res) {
//console.log(require('./number.json'))
var fs = require('fs')
fs.readFile('./number.json', {encoding: 'utf-8'}, function(err,data){
if (!err) {
//console.log('received data: ' + JSON.parse(data));
res.json(JSON.parse(data))
} else {
console.log(err);
}})
})
app.post('/api/num', function(req, res) {
var id = req.body.id
var fs = require('fs');
fs.writeFileSync("./number.json", "[ "+id+" ]", function(err) {
if(err) {
return console.log(err);
}
res.status(200)
})
})
Thanks for all the help :)
fs.writeFileSync doesn't have a callback, so the function you're adding never gets executed: https://nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options
This means the response is never sent back to the client, and the axios promise is never resolved.
Try using fs.writeFile with a callback: https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
It's also a good idea to send a response in the case of an error, too.
app.post('/api/num', function(req, res) {
var id = req.body.id
var fs = require('fs');
fs.writeFile("./number.json", "[ "+id+" ]", function(err) {
if(err) {
console.log(err);
return res.status(200)
}
res.status(200)
})
})
Finally, though it wouldn't help you in this situation, you should add a .catch to the very tail end of your axios chain. Any errors that take place in the promise chain will wind up there.
An example:
axios.get(specs).then(someFunction).catch(e => console.error(e));
for me I was facing the same issue and I figured it out that because I'm using some redirection after making a post request
window.location.href = "/{redirect to some rout}"
this makes the console change immediately so I couldn't see the then response unless I removed the redirection.
I too faced an issue where I wasn't able to run the .then() or .catch() code
const fetch = async() => {
axios.get("https://jsonplaceholder.typicode.com/todos/1")
.then((res) => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.24.0/axios.min.js"></script>
All I did was add async to the function and it started working
const axios = require('axios').default;
use it like this

Catching a try error inside an async callback

I'm using a callback to set some ip's on redis db async.
I'm trying to catch the error and send it through express to my error handler middleware.
I'm generating an error on purpose on the select method, but it doesn't catch my error.
See following code:
module.exports = (req, res, next) => {
const redis = require('redis')
const client = redis.createClient()
try {
client.select('2d', (err) => { // instead of 2 number, i use '2d' string, to generate an error on purpose
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
client.set(ip, true, 'EX', 120, (err, rep) => {
return next()
})
})
} catch (err) {
err.type = 'SilentSystem'
next(err)
}
}
From the documentation of the redis npm package, it's clear that it uses standard Node-style callbacks. In a standard Node-style callback, the first argument passed to the callback you provide is either an error or null; that's where and how errors are reported. (You've even defined a parameter called err in your code.) They can't be caught by a try/catch because control has already passed out of the try/catch (and in fact out of the function it's in) long before the error occurs.
So you'd handle it like this:
module.exports = (req, res, next) => {
const redis = require('redis')
const client = redis.createClient()
client.select('2d', (err) => { // instead of 2 number, i use '2d' string, to generate an error on purpose
if (err) {
// Handle error here
err.type = 'SilentSystem'
next(err)
} else {
// Handle success here
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
client.set(ip, true, 'EX', 120, (err, rep) => {
if (err) {
err.type = 'SilentSystem'
next(err)
} else {
next()
}
})
}
})
}
In a comment you've said:
My actual code is a bit more complex so I was trying to avoid calling to avoid repeating calling if(err) and next(err) by using try. What's a better way (less verbose) to handle errors here?
Unfortunately, that's the nature of Node-style callbacks. One option is to give yourself a filtering function you pass all those results through so your common error-handling code is there.
But: You might consider using a lib that "promisifies" Node-style callbacks so you can use promises instead, complete with their chaining mechanism which makes centralized error handling possible. (One such package is promisify, but there are others.) With "promisified" versions of client.select, client.set., etc., that code could look like this:
module.exports = (req, res, next) => {
const redis = require('redis')
const client = makeNiftyPromiseVersionOf(redis.createClient())
client.select('2d')
.then(data => {
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
return client.set(ip, true, 'EX', 120)
})
.then(() => {
next()
})
.catch(err => {
err.type = 'SilentSystem'
next(err)
})
}
Note how the error handling is consolidated at the end; if there's an error in client.select, the then callback is skipped and control passes to the catch. If not, the then callback is executed and client.set is performed, and any errors from it will also go to that catch.
This also opens the door to using ES2017's async/await to write asynchronous code in a synchronous style:
module.exports = (req, res, next) => {
(async () => {
const redis = require('redis')
const client = makeNiftyPromiseVersionOf(redis.createClient())
try {
const data = await client.select('2d');
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
await client.set(ip, true, 'EX', 120)
next()
} catch (err) {
err.type = 'SilentSystem'
next(err)
}
})();
}
Side note: I would remove the require call out of the exported function, and instead do it at the module level:
const redis = require('redis')
module.exports = {
// ...
}

Categories

Resources