apiCall.js

"use strict";

const request = require("superagent");
const binaryParser = require("superagent-binary-parser");
const _ = require('private-parts').createKey();
const GRANT_TYPES = require("./grantTypes");
const CONT_TYPES = require("./callTypes");

/** Manage response from Chino API
 *
 * @param error
 * @param response
 */
function responseHandler(error, response) {
  if (error) {
    this.reject(response.body || error);
  }
  else {
    this.resolve(response.body);
  }
}

class Call {
  /** Create a Call object
   * @constructor
   * @param baseUrl {string}
   * @param id      {string}
   * @param secret  {string | object}
   */
  constructor(baseUrl = "", authId = "", authSecret = "") {
    this.baseUrl = baseUrl;

    // set private properties
    _(this).id = authId;
    _(this).secret = authSecret;
  }

  /** Make GET request to Chino APIs
   *
   * @param url         {string}
   * @param params      {object}
   * @return {Promise}
   */
  get(url, params = {}) {
    let makeCall = (resolve, reject) => {
      request
          .get(this.baseUrl + url)
          .auth(_(this).id, _(this).secret)
          .type("application/json")
          .accept("application/json")
          .query(params)
          .end(responseHandler.bind({resolve, reject}));
    }

    return new Promise(makeCall);
  }

  /** Make GET request to Chino APIs
   *  to retrieve blob data
   *
   * @param url         {string}
   * @param params      {object}
   * @return  {request}
   */
  getBlob(url, params = {}) {
      return request
          .get(this.baseUrl + url)
          .auth(_(this).id, _(this).secret)
          .type("application/json")
          .accept("application/octet-stream")
          .query(params)
          .buffer(true)
          .parse(binaryParser)
  }

  /** Make POST request to Chino APIs
   *
   * @param url         {string}
   * @param data        {object}
   * @param acceptType  {string | null}
   * @return {Promise}
   */
  post(url, data = {}, acceptType = null) {
    let makeCall = (resolve, reject) => {
      // prepare the request and then send it
      const req = request
                    .post(this.baseUrl + url)
                    .auth(_(this).id, _(this).secret);

      // error data in used in case of data is empty or miss any property
      const missingFieldException = {
        message : "Trying to make request with wrong or empty data",
        result_code : 400,
        result : "error",
        data : null
      };

      if (acceptType === CONT_TYPES.FORM_DATA) {
        req
          .set("Content-Type", "multipart/form-data")
          .accept("multipart/json");

        // set form fields
        switch (data["grant_type"]) {
          case GRANT_TYPES.PASSWORD:
            if (data["username"] && data["password"]) {
              req
                .field("grant_type", "password")
                .field("username", data["username"])
                .field("password", data["password"])
            }
            else {
              throw missingFieldException;
            }
            break;
          case GRANT_TYPES.AUTH_CODE:
            if (data["code"] && data["redirect_url"] &&
                data["client_id"] && data["client_secret"] ) {

                req
                  .field("grant_type", data["grant_type"])
                  .field("code", data["code"])
                  .field("redirect_url", data["redirect_url"])
                  .field("client_id", data["client_id"])
                  .field("client_secret", data["client_secret"])
                  .field("scope", "read write")
            }
            else {
              throw missingFieldException;
            }
            break;
          case GRANT_TYPES.RFS_TOKEN:
            if (data["token"] && data["client_id"] && data["client_secret"]) {
              req
                  .field("grant_type", "refresh_token")
                  .field("refresh_token", data["token"])
                  .field("client_id", data["client_id"])
                  .field("client_secret", data["client_secret"])
            }
            else {
              throw missingFieldException;
            }
            break;
          case GRANT_TYPES.REVOKE:
            if (data["token"] && data["client_id"] && data["client_secret"]) {
              req
                  .field("token", data["token"])
                  .field("client_id", data["client_id"])
                  .field("client_secret", data["client_secret"])
            }
            else {
              throw missingFieldException;
            }
            break;
          default:
            throw {
              message : "No grant type selected",
              result_code : 400,
              result : "error",
              data : null
            };
        }
      }
      else {
        req
          .type("application/json")
          .accept("application/json")
          .send(data)
      }

      req.end(responseHandler.bind({resolve, reject}));
    }

    return new Promise(makeCall);
  }

  /** Make PUT request to Chino APIs
   *
   * @param url         {string}
   * @param data        {object}
   * @param params      {object}
   * @return {Promise}
   */
  put(url, data = {}, params = {}) {
    let makeCall = (resolve, reject) => {
      request
        .put(this.baseUrl + url)
        .auth(_(this).id, _(this).secret)
        .type("application/json")
        .accept("application/json")
        .send(data)
        .end(responseHandler.bind({resolve, reject}));
    }

    return new Promise(makeCall);
  }

  /** Make PUT request to Chino APIs
   *  sending data as octet stream
   *
   * @param url         {string}
   * @param data        {object}
   * @param params      {object}
   * @return {Promise}
   */
  chunk(url, data = {}, params = {}) {
    let makeCall = (resolve, reject) => {
      request
          .put(this.baseUrl + url)
          .auth(_(this).id, _(this).secret)
          .set("offset", params.blob_offset)
          .set("length", params.blob_length)
          .type("application/octet-stream")
          .accept("application/json")
          .send(data)
          .end(responseHandler.bind({resolve, reject}));
    }

    return new Promise(makeCall);
  }

  /** Make PATCH request to Chino APIs
   *
   * @param url   {string}
   * @param data  {object}
   * @return {Promise}
   */
  patch(url, data = {}) {
    let makeCall = (resolve, reject) => {
      request
          .patch(this.baseUrl + url)
          .auth(_(this).id, _(this).secret)
          .type("application/json")
          .accept("application/json")
          .send(data)
          .end(responseHandler.bind({resolve, reject}));
    }

    return new Promise(makeCall);
  }


  /** Make DELETE request to Chino APIs
   *
   * @param url     {string}
   * @param params  {object}
   * @return {Promise}
   */
  del(url, params = {}) {
    let makeCall = (resolve, reject) => {
      request
          .del(this.baseUrl + url)
          .auth(_(this).id, _(this).secret)
          .type("application/json")
          .accept("application/json")
          .query(params)
          .end(responseHandler.bind({resolve, reject}));
    }

    return new Promise(makeCall);
  }
}

module.exports = Call;