yoctore/yocto-orika

View on GitHub
src/api/core/request.js

Summary

Maintainability
B
6 hrs
Test Coverage
'use strict';

var joi     = require('joi');
var logger  = require('yocto-logger');
var _       = require('lodash');
var Q       = require('q');
var utils   = require('yocto-utils');
var request = require('request');

/**
 * Default core class. Prepare / process & send request with given data
 */
function ApiRequest (l) {
  /**
   * Default logger instance
   */
  this.logger   = l;
}

/**
 * Default method to prepare request before orika api call
 *
 * @param {String} host host to call
 * @param {Object} data default data to use on request
 * @return {Boolean} true if all is ok false otherwise
 */
ApiRequest.prototype.prepare = function (host, data) {
  // default validation schema
  var schema = joi.object().keys({
    user    : joi.string().required().empty(),
    pwd     : joi.string().required().empty(),
    data    : joi.object().required().min(1),
    // Used only for orkarte
    action  : joi.string().optional().empty()
  }).allow([ 'user', 'pwd', 'data' ]);

  // validate currenr schema
  var validate = joi.validate(data, schema, { abortEarly : false });

  // has error ?
  if (!_.isEmpty(validate.error) || !_.isString(host) || _.isEmpty(host)) {
    // log error message
    this.logger.error([ '[ YoctoOrika.ApiRequest.prepare ] - Invalid data given :',
                         validate.error || 'host is invalid' ].join(' '));
    // invalid statement
    return false;
  }

  // default statement
  return true;
};

/**
 * Default method to process a request on end api
 *
 * @param {String} host given host to use
 * @param {String} endpoint given endpoint to use
 * @param {String} method given method to use
 * @param {Object} required config params given by config class
 * @param {Object} data data to send on request
 * @param {Boolean} methodInUrl Indicate if the method should be added into url
 * @return {Object} default promise to use on the end of request
 */
ApiRequest.prototype.process = function (host, endpoint, method, required, data, methodInUrl) {
  // create async process
  var deferred = Q.defer();

  // normalize host
  host = methodInUrl ? [ host, endpoint, method ].join('/') : [ host, endpoint ].join('/');

  // default merged data to use
  data = _.merge(_.clone(required), { data : data });
  // prepare request
  if (this.prepare(host, data)) {
    // debug message
    this.logger.debug([ '[ YoctoOrika.ApiRequest.process ] - Processing a POST request to :',
                         host, 'with data below :', utils.obj.inspect(data) ].join(' '));
    // process request
    request({
      json    : true,
      method  : 'POST',
      uri     : host,
      body    : data
    }, function (error, response, body) {
      // log response before validation
      this.logger.debug([ '[ YoctoOrika.ApiRequest.process ] -',
                          'Receiving response with data below :',
                          utils.obj.inspect(body) ].join(' '));
      // add test to check if all is ok for next process
      if (!error && response && _.has(response, 'statusCode') && response.statusCode === 200) {
        // return with correct data
        deferred.resolve(body);
      } else {
        // normalize error
        error = error || [
          response.statusCode     || 'Cannot find request status message',
          response.statusMessage  || 'Cannot find request message'
        ].join(' ');

        // log message
        this.logger.error([ '[ YoctoOrika.ApiRequest.process ] - Http request error :',
                            error ].join(' '));
        // reject with data
        deferred.reject(error);
      }
    }.bind(this));
  } else {
    // log error
    this.logger.error([ '[ YoctoOrika.ApiRequest.process ] - Cannot process request for', method,
                        'method.', 'Cannot prepare data with given value :',
                        utils.obj.inspect(_.values(arguments))
                      ].join(' '));
    // reject
    deferred.reject();
  }

  // default statement
  return deferred.promise;
};

// Default export
module.exports = function (l) {
  // is a valid logger ?
  if (_.isUndefined(l) || _.isNull(l)) {
    // warning message
    logger.warning([ '[ YoctoOrika.ApiRequest.constructor ] -',
                     'Invalid logger given. Use internal logger' ].join(' '));
    // assign
    l = logger;
  }

  // default statement
  return new (ApiRequest)(l);
};