jcready/http-as-promised

View on GitHub
http.promise.js

Summary

Maintainability
D
2 days
Test Coverage
'use strict';

var Promise = require('bluebird'),
  onPossiblyUnhandledRejection = Promise.onPossiblyUnhandledRejection.bind(Promise),
  onUnhandledRejectionHandled = Promise.onUnhandledRejectionHandled.bind(Promise),
  longStackTraces = Promise.longStackTraces.bind(Promise),
  HTTP_METHODS = {
    post  : 'POST',
    put   : 'PUT',
    patch : 'PATCH',
    head  : 'HEAD',
    del   : 'DELETE',
    get   : 'GET'
  },
  reqMethods = [
    'get', 'head', 'post', 'put',
    'patch', 'del', 'jar', 'cookie'
  ],
  defaultOptions = {
    error: true,
    method: 'GET'
  };

module.exports = (function wrapRequest(request, defaultOpts){
  reqMethods.forEach(function (method){
    HTTP[method] = HTTP_METHODS.hasOwnProperty(method)
                 ? wrapMethod(HTTP_METHODS[method])
                 : request[method].bind(request);
  });

  HTTP.defaults = setDefaults;
  HTTP.onPossiblyUnhandledRejection = onPossiblyUnhandledRejection;
  HTTP.onUnhandledRejectionHandled = onUnhandledRejectionHandled;
  HTTP.longStackTraces = longStackTraces;
  Object.defineProperties(HTTP, {
    error: {
      value: require('./http.error'),
      enumerable: false,
      configurable: false,
      writable: false
    },
    request: {
      value: request,
      enumerable: false,
      configurable: false,
      writable: false
    },
    debug: {
      get: function() { return request.debug },
      set: function(v){ return request.debug = v },
      enumerable: true
    }
  });

  function HTTP(options, extra){
    var opts = setOptions(options, extra);
    opts.method = opts.method.toUpperCase();
    return new Promise(function HTTP_PROMISE(resolve, reject) {
      request(opts, function HTTP_RESPONSE(error, response, body) {
        if (error) {
          error.options = opts;
          error.statusCode = 0;
          error.title = 'Invalid Request';
          error.summary = 'failed to perform HTTP request';
          reject(error);
        } else if (opts.error && (response.statusCode === 0 || response.statusCode >= 400)) {
          var statusCode = response.statusCode;
          var HTTPErr = HTTP.error.hasOwnProperty(statusCode)
                      ? HTTP.error[statusCode]
                      : statusCode < 500
                        ? HTTP.error.client
                        : statusCode < 600
                          ? HTTP.error.server
                          : HTTP.error;
          var httpErr = new HTTPErr;
          httpErr.body = body;
          httpErr.options = opts;
          httpErr.response = response;
          httpErr.statusCode = statusCode;
          Object.defineProperty(httpErr, 'response', {
            value: response,
            enumerable: false,
            configurable: false,
            writable: false
          });
          reject(httpErr);
        } else {
          if (typeof opts.transform === 'function') {
            body = opts.transform(response, body);
          }
          if (!opts.resolve) {
            resolve([response, body]);
          } else if (opts.resolve === 'body') {
            resolve(body);
          } else if (opts.resolve === 'response') {
            resolve(response);
          } else if (Array.isArray(opts.resolve)
                  && opts.resolve.length === 2
                  && opts.resolve[0] === 'body'
                  && opts.resolve[1] === 'response') {
            resolve([body, response]);
          } else {
            resolve([response, body]);
          }
        }
      });
    });
  }

  function wrapMethod(method){
    return function HTTP_METHOD(options, extra){
      var opts = setOptions(options, extra, method);
      return HTTP(opts);
    }
  }

  function setDefaults(defaults){
    var current = assign({}, defaultOpts);
    return wrapRequest(
      request.defaults(defaults),
      assign(current, defaults)
    );
  }

  function setOptions(options, extra, method){
    var opts = assign(assign({}, defaultOpts), options);
    if (typeof options === 'string') {
      opts = assign(opts, extra);
      opts.uri = options;
    }
    opts.method = method || opts.method;
    return opts;
  }

  return HTTP;
})(require('request'), defaultOptions);

function assign(target, extension){ /*eslint-disable curly*/
  if (typeof extension === 'object' && extension !== null)
    for (var k in extension)
      if (extension.hasOwnProperty(k))
        target[k] = extension[k];
  return target;
}