polyfills | | Cell 1 | Search

This code defines a httpRequest function that makes HTTP requests using either the request module (if available) or a custom implementation based on the http and https modules.

Run example

npm run import -- "https request"

https request

var promisify
try {
    promisify = require('util').promisify
} catch (e) {
    if(!e.message.includes('Cannot find module')) {
        throw e
    }
}
if(!promisify) {
    try {
        promisify = require('bluebird').promisify
    } catch (e) {
        if(!e.message.includes('Cannot find module')) {
            throw e
        }
    }    
}

try {
    var httpRequest = util.promisify(require('request'));
} catch (e) {
    if(!e.message.includes('Cannot find module')) {
        throw e
    }
    
    var http = require('http')
    var https = require('https')
    var url = require('url')

    function httpRequest(params) {
        var protocol = params.url.includes('http://') ? http : https
        var location = url.parse(params.url)
        var postData = querystring.stringify(params.data);

        Object.assign(params, {
            path: location.pathname,
            host: location.hostname,
            port: location.port || location.protocol === 'http' ? 80 : 443,
            headers: Object.assign(params.headers || {}, {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': Buffer.byteLength(postData)
            }, params.headers)
        }, params)

        return new Promise(function(resolve, reject) {
            var req = protocol.request(params, function(res) {
                // cumulate data
                res.setEncoding('utf8');                
                res.body = [];
                res.on('data', function(chunk) {
                    res.body.push(chunk);
                });
                // resolve on end
                res.on('end', function() {
                    try {
                        res.body = res.body.join('');
                    } catch(e) {
                        reject(e);
                    }
                    resolve(res);
                });
            });
            req.on('error', err => reject(err));
            if (params.data) {
                req.write(postData);
            }
            // IMPORTANT
            req.end();
        });
    }
}

function request(...args) {
    return httpRequest(...args)
        .then(res => {
            if(res.statusCode < 200 || res.statusCode >= 300) {
                throw new Error('Error: ' + res.statusCode + ' - ' + JSON.stringify(res.body));
            }
            var isJson = (res.headers['content-type'] || '').match(/application\/json/ig);
            var isPlain = (res.headers['content-type'] || '').match(/text\//ig);
            if(isJson && typeof res.body !== 'undefined') {
                try {
                    res.body = JSON.parse(res.body.toString('utf8'));
                } catch (e) {}
            }
            if(isPlain && typeof res.body !== 'undefined') {
                res.body = res.body.toString('utf8');
            }
            return res;
        })
}

module.exports = {
    request
}

What the code could have been:

const util = require('util');
const querystring = require('querystring');
const https = require('https');
const http = require('http');
const url = require('url');

// Try to use promisify from util if available
const promisify = util.promisify || (() => {
  // If not, try to use promisify from bluebird if installed
  try {
    return require('bluebird').promisify;
  } catch (error) {
    // If bluebird is not installed, throw the error
    if (!error.message.includes('Cannot find module')) {
      throw error;
    }
    // If bluebird is not installed, do not throw any error
    return util.promisify;
  }
})();

// Promisify the request function
const request = promisify(require('request'));

// Function to create a promise-based version of request
function httpRequest(params) {
  // Check if the promise is already created
  if (params instanceof Promise) {
    return params;
  }

  // Extract the protocol, location and data from the params
  const protocol = params.url.includes('http://')? http : https;
  const location = url.parse(params.url);
  const postData = querystring.stringify(params.data);

  // Create a new params object with the path, host, port and headers
  const newParams = {
    path: location.pathname,
    host: location.hostname,
    port: location.port || (location.protocol === 'http:'? 80 : 443),
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': Buffer.byteLength(postData)
    }
  };

  // Merge the new params with the original params
  Object.assign(newParams, params);

  // Return a new promise
  return new Promise((resolve, reject) => {
    // Create a new request
    const req = protocol.request(newParams, (res) => {
      // Cumulate the data
      res.setEncoding('utf8');
      res.body = [];
      res.on('data', (chunk) => {
        res.body.push(chunk);
      });

      // Resolve the promise on end
      res.on('end', () => {
        try {
          // Join the body chunks
          res.body = res.body.join('');
        } catch (error) {
          // Reject the promise if an error occurs
          reject(error);
        }
        // Resolve the promise with the response
        resolve(res);
      });
    });

    // Handle errors
    req.on('error', (error) => reject(error));

    // Write the data if it exists
    if (params.data) {
      req.write(postData);
    }

    // End the request
    req.end();
  });
}

// Function to handle the response
function handleResponse(res) {
  // Check the status code and throw an error if it's not between 200 and 300
  if (res.statusCode < 200 || res.statusCode >= 300) {
    throw new Error(`Error: ${res.statusCode} - ${JSON.stringify(res.body)}`);
  }

  // Check if the response is JSON
  const isJson = (res.headers['content-type'] || '').match(/application\/json/ig);
  const isPlain = (res.headers['content-type'] || '').match(/text\//ig);

  // Parse the body as JSON if it's a JSON response
  if (isJson && typeof res.body!== 'undefined') {
    try {
      res.body = JSON.parse(res.body.toString('utf8'));
    } catch (error) {
      // Do nothing if an error occurs
    }
  }

  // Set the body as a string if it's a plain text response
  if (isPlain && typeof res.body!== 'undefined') {
    res.body = res.body.toString('utf8');
  }

  // Return the response
  return res;
}

// Export the request function
module.exports = {
  request: (options) => {
    // Call the request function with the options
    return httpRequest(options).then(handleResponse);
  }
};

This code snippet aims to provide a promisified httpRequest function for making HTTP requests, handling potential errors gracefully and falling back to a custom implementation if the util.promisify or bluebird libraries are not available.

Here's a breakdown:

  1. promisify Detection and Fallback:

  2. httpRequest Function:

  3. Custom httpRequest Implementation:

In essence, this code provides a robust and flexible way to make HTTP requests in a Promise-based manner, gracefully handling potential dependency issues.