How catch errors in nested async functions

Viewed 280

I'm trying to catch an error in nested async functions to make a rollback if there is an error.

So I have my first try catch, then inside it I call a function that call another function, the last function should throw an error, I thought that the first try bloc gonna catch the throw error, but he doesn't. This is my code :

The function with the first try/catch :

exports.add = (req, res) => {
    const { product, type } = req.body

    try {
        switch (type) {
            case ProductsTypes.TRACK:
                addTrack(product, req.files)
                res.status(200).json({ message: 'SUCCESS !' })
                break
            default:
                res.status(400).json({ message: 'INVALID TYPE !' })
        }
    } catch (error) {
        // ROLLBACK HERE
        res.status(400).json({ message: "Error Exception, Need to rollback", error })
    }
}

The function where I thought to catch the error to return it to the top

const addTrack = (product, files) => {
    const imageFile = files[NamesAddTrackForm.TRACK_IMAGE][0]
    const audioFile = files[NamesAddTrackForm.TRACK_AUDIO][0]
    const stemsZip = files[NamesAddTrackForm.TRACK_STEMS][0]

    FilesFormater.resizeImage(imageFile, 500, 500) // I thought this function throw an exception
}

The function where I throw the error :

resizeImage = (file, width, height) => {
    try {
        sharp(file.path)
            .resize(width, height)
            .jpeg({ quality: 90 })
            .toBuffer((err, buffer) => {
                fs.writeFileSync(file.path, buffe, (err) => { // I simulate an error here (buffe) instead (buffer)
                    if (!err) {
                        throw Error(err)
                    }
                })
            })
    } catch (error) {
        throw Error(error)
    }
}

I would like to know how to be able to handle this kind of errors to send it back to the first one, because I would like to use this logic in my other files in order to rollback actions like inserting in the database, or creating files, if an error appears during the processing of the code, because otherwise I end up with illogical data

1 Answers

You need to make resizeImage to return a Promise if you want to catch the Error from an asynchronous operation.

Also, you need to add async keyword in the function, so that you can use await.

You may try like below: (Code not tested.)

const fs = require("fs").promises;

class FilesFormater {
    static resizeImage = async (file, width, height) => {
        try {
            const { data } = await sharp(file.path)
                .resize(width, height)
                .jpeg({ quality: 90 })
                .toBuffer();

            await fs.writeFile(file.path, data);
        } catch (error) {
            throw new Error(error);
        }
    };
}

const addTrack = (product, files) => {
    const imageFile = files[NamesAddTrackForm.TRACK_IMAGE][0];
    const audioFile = files[NamesAddTrackForm.TRACK_AUDIO][0];
    const stemsZip = files[NamesAddTrackForm.TRACK_STEMS][0];

    return FilesFormater.resizeImage(imageFile, 500, 500); // a Promise is return.
};

exports.add = async (req, res) => {
    const { product, type } = req.body;

    try {
        switch (type) {
            case ProductsTypes.TRACK:
                await addTrack(product, req.files); // await the Promise
                res.status(200).json({ message: "SUCCESS !" });
                break;
            default:
                res.status(400).json({ message: "INVALID TYPE !" });
        }
    } catch (error) {
        // ROLLBACK HERE
        res.status(400).json({
            message: "Error Exception, Need to rollback",
            error,
        });
    }
};
Related