cloudinary_npm icon indicating copy to clipboard operation
cloudinary_npm copied to clipboard

Library should reject with Error objects

Open TheFarmer1 opened this issue 8 years ago • 6 comments

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.

TheFarmer1 avatar Jan 20 '17 00:01 TheFarmer1

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.

roeeba avatar Feb 09 '17 11:02 roeeba

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:

  • the code is es2015 - so if you want to use it you need node6+ or babel (or rewrite it!)
  • I'm only interested in the promise-based interface (callbacks do not work with this hack)
  • it's rough'n'ready, there are problably scenarios/methods/situations I've missed!
  • use at your own risk[tm]

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);

iamjochem avatar Jul 27 '17 15:07 iamjochem

@roeeba Is there any progress on this?

TheDancingCode avatar May 16 '18 07:05 TheDancingCode

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.

roeeba avatar May 23 '18 10:05 roeeba