ajax.js

/**
 * Default options for the ajax.
 *
 * @private
 * @type {Object}
 */
const defaults = {
    responseType: 'json'
};

/**
 * A function to perform ajax requests. It returns promise instead of relying on callbacks.
 *
 * @example
 * ATV.Ajax('http://api.mymovieapp.com/movies')
 *     .then((response) => // do something with the response)
 *     .catch((error) => // catch errors )
 *
 * @memberof module:ajax
 * 
 * @param  {String} url                                 Resource url
 * @param  {Object} [options={responseType: 'json'}]    Options to apply for the ajax request
 * @param  {String} [method='GET']                      Type of HTTP request (defaults to GET)
 * @return {Promise}                                     The Promise that resolves on ajax success
 */
function ajax(url, options, method = 'GET') {
    if (typeof url == 'undefined') {
        console.error('No url specified for the ajax.');
        throw new TypeError('A URL is required for making the ajax request.');
    }

    if (typeof options === 'undefined' && typeof url === 'object' && url.url) {
        options = url;
        url = options.url;
    } else if (typeof url !== 'string') {
        console.error('No url/options specified for the ajax.');
        throw new TypeError('Options must be an object for making the ajax request.');
    }

    // default options
    options = Object.assign({}, defaults, options, {method: method});

    console.log(`initiating ajax request... url: ${url}`, ' :: options:', options);

    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();

        // set response type
        if (options.responseType) {
            xhr.responseType = options.responseType;
        }
        // open connection
        xhr.open(
            options.method,
            url,
            typeof options.async === 'undefined' ? true : options.async,
            options.user,
            options.password
        );
        // set headers
        Object.keys(options.headers || {}).forEach(function(name) {
            xhr.setRequestHeader(name, options.headers[name]);
        });
        // listen to the state change
        xhr.onreadystatechange = () => {
            if (xhr.readyState !== 4) {
                return;
            }

            if (xhr.status >= 200 && xhr.status <= 300) {
                resolve(xhr);
            } else {
                reject(xhr);
            }
        };
        // error handling
        xhr.addEventListener('error', () => reject(xhr));
        xhr.addEventListener('abort', () => reject(xhr));
        // send request
        xhr.send(options.data);
    });
}

Object.assign(ajax, {
    /**
     * Perform an ajax request using HTTP GET
     *
     * @example
     * ATV.Ajax.get('http://api.mymovieapp.com/movies')
     *         .then((response) => // do something with the response)
     *         .catch((error) => // catch errors )
     *
     * @alias module:ajax.get
     *
     * @param  {string} url                         Resource url
     * @param  {Object} [options={@link defaults}]  Ajax options
     * @return {Promise}                            The Promise that resolves on ajax success
     */
    get(url, options) {
        return ajax(url, options, 'GET');
    },
    /**
     * Perform an ajax request using HTTP POST
     *
     * @example
     * ATV.Ajax.post('http://api.mymovieapp.com/movies', {data})
     *         .then((response) => // do something with the response)
     *         .catch((error) => // catch errors )
     *
     * @alias module:ajax.post
     *
     * @param  {string} url                         Resource url
     * @param  {Object} [options={@link defaults}]  Ajax options
     * @return {Promise}                            The Promise that resolves on ajax success
     */
    post(url, options) {
        return ajax(url, options, 'POST');
    },
    /**
     * Perform an ajax request using HTTP PUT
     *
     * @alias module:ajax.put
     *
     * @param  {string} url                         Resource url
     * @param  {Object} [options={@link defaults}]  Ajax options
     * @return {Promise}                            The Promise that resolves on ajax success
     */
    put(url, options) {
        return ajax(url, options, 'PUT');
    },
    /**
     * Perform an ajax request using HTTP DELETE
     *
     * @alias module:ajax.del
     *
     * @param  {string} url                         Resource url
     * @param  {Object} [options={@link defaults}]  Ajax options
     * @return {Promise}                            The Promise that resolves on ajax success
     */
    del(url, options) {
        return ajax(url, options, 'DELETE');
    }
});

/**
 * A very minimalistic AJAX implementation that returns promise instead of relying in callbacks.
 *
 * @module ajax
 *
 * @author eMAD <emad.alam@yahoo.com>
 *
 */
export default ajax;