cloudinary / cloudinary_npm

Cloudinary NPM for node.js integration
625 stars 321 forks source link

Library should reject with Error objects #131

Open TheFarmer1 opened 7 years ago

TheFarmer1 commented 7 years ago

Rejects, callbacks, exceptions are coming back with plain object that looks like: {error: {http_code:404, message: "some message"}}. It should be an instance of Error class.

roeeba commented 7 years ago

Hi @TheFarmer1 , thank you for pointing this out. We're aware of this issue and we plan to resolve it as soon as we can. We will update here once this resolved.

iamjochem commented 7 years ago

I guess this does not have much priority, I'm surprised it's not been addressed. For anyone wishing to work around the lack of real Errors I offer the following hack:

some caveats:

hope it helps someone.

hack_cloudinary_api.js:

const P             = require('bluebird');
const each          = require('lodash/each');
const isfunc        = require('lodash/isFunction');
const isstr         = require('lodash/isString');
/**
 * hack cloudinary api so that errors rejected via it's promise interface are automatically
 * converted to real Error instances, also upgrades the promises to bluebird Promises
 *
 * @param  {Object} api
 * @return {void}
 */
module.exports = function hack_cloudinary_api(api)
{
    /**
     * helper for generating a real Error object from the
     * cruft that cloudinary emits - the generated Error is always thrown!
     *
     * @param  {mixed} eo   - string or object literal (with a nubmer of different possible structures)
     * @return {void}
     * @throws {Error}
     */
    function throw_real_error(eo)
    {

        if (eo instanceof Error) {
            eo.message = gen_real_error_msg(eo.message);
            throw eo;
        }

        if (isstr(eo))
            throw new Error(gen_real_error_msg(eo));

        const got_err_prop = (eo && eo.error);

        if (got_err_prop && (eo.error instanceof Error))
            throw eo.error;

        const tmp = got_err_prop ? eo.error : eo;

        if (tmp && tmp.message) {
            const err = new Error(gen_real_error_msg(tmp.message));

            if (tmp.http_code)
                err.httpcode = tmp.http_code;

            throw err;
        }

        throw new Error(gen_real_error_msg('unknown error occurred'));
    }

    /**
     * helper for throw_real_error()
     *
     * @param  {String} msg [description]
     * @return {String}     [description]
     */
    function gen_real_error_msg(msg)
    {
        return `Cloundinary API: ${msg}`;
    }

    each(api, (fn, k) => {
        if (!isfunc(fn) || fn.length < 2)
            return;

        api[k] = (...args) => P.try(() => fn.call(api, ...args).catch(eo => throw_real_error(eo)));
    });
}

example of usage:

const hack_cloudinary_api = require('./hack_cloudinary_api');
const cloudinary = require('cloudinary');

const cloudconf = { /* your cloudinary config/setting here! */ };
const cloudinst = cloudinary.init( cloudconf );

hack_cloudinary_api(cloudinst.api);
hack_cloudinary_api(cloudinst.uploader);
TheDancingCode commented 6 years ago

@roeeba Is there any progress on this?

roeeba commented 6 years ago

Hi @TheDancingCode, Sorry for the delayed reply. I've checked it internally and there's no ETA we can currently guarantee. I'll update as soon as we'll have one.

yoniheib commented 5 months ago

We just encountered this issue ourselves - caused an issue when reporting errors with Sentry, which expects Error objects when capturing exceptions. Any update on a fix for this?

tommyg-cld commented 4 months ago

@yoniheib no new updates i'm afraid, this is still in our backlog.