Crate API done hook

@inner
@param {Function} done the done hook to execute
@param {Object} ctx the extra call context for the hook
@return {Object}
function createAPIDoneHook(done, ctx) {
    let hookInfo = {
        resData: null,
        resException: false,
        hook: null
    };

    hookInfo.hook = (err, res, complete, shouldCatchException) => {
        let result;
        if (err != null) {
            result = err;
            if (shouldCatchException) {
                try {
                    let data = done(result, null, ctx);
                    data == null || (result = data);
                }
                catch (ex) {
                    // cache exception info for promise
                    hookInfo.resException = true;
                    result = ex;
                }
            }
            else {
                let data = done(result, null, ctx);
                data == null || (result = data);
            }
        }
        else {
            let data = done(null, res, ctx);
            data == null || (res = data);
            result = res;
        }

        // cache response data for promise
        hookInfo.resData = result;

        complete && complete(result); // call complete callback

        return result;
    };

    return hookInfo;
}