Home Reference Source

src/client.js

import axios from "axios";
import * as errors from "./errors";

axios.defaults.adapter = "http";

/**
 * A client for generating data using mockaroo.
 */
export default class Client {
  /**
     * Creates a new instance
     * @param {Object} options
     * @param {string} options.apiKey Your mockaroo api key. See http://mockaroo.com/api/docs under "Gaining Access".
     * @param {string} [options.host='mockaroo.com'] The hostname of the mockaroo server.
     * @param {int} [options.port=80] The port to use.
     * @param {boolean} [options.secure=true] Set to false to use http instead of https
     */
  constructor (options) {
    const defaults = {
      host: "api.mockaroo.com",
      secure: true,
      port: null,
      apiKey: null
    };

    Object.assign(this, defaults, options);

    this.validate();
  }

  /**
     * Generates data based on the specified options. You can use either a saved schema using the "schema" option:
     *
     * @example
     *
     *  // generate data from a saved schema
     *  client.generate({
     *    schema: 'My Saved Schema'
     *  }).then(function(data) {
     *     // keys are the names of the columns in your saved schema.
     *  })
     *
     * @example
     *
     *  //specify fields using the api
     *  client.generate({
     *    count: 10,
     *    fields: [{
     *      name: 'id'
     *      type: 'Row Number',
     *    }, {
     *      name: 'transactionType'
     *      type: 'Custom List',
     *      values: ['debit', 'credit']
     *    }, {
     *      name: 'amount',
     *      type: 'Number'
     *      min: 1
     *      max: 10000,
     *      decimals: 2
     *    }]
     *  }).then(function(data) {
     *    for (var i=0; i<data.length; i++) {
     *      var record = data[i];
     *      console.log('id', record.id, 'transactionType', record.transactionType, 'amount', record.amount);
     *    }
     *  })
     *
     *
     * @typedef {Object} Field
     * @property {string} type The type of field. Many field types such as "Number" and "Custom List" take additional parameters, which are documented here: http://mockaroo.com/api/docs#types.
     * @property {string} name The value will be returned under this key in the resulting data objects.
     *
     * @param {Object} options
     * @param {int} [options.count=1] The number of records to generate. See usage limits here: http://mockaroo.com/api/docs
     * @param {string} options.schema The name of the saved schema. Use this to generate data based on schema you've built using the website.  Use the fields array to generate data using an ad-doc schema.
     * @param {string} [options.format='json'] 'json' by default, set to 'csv' to generate csv data.
     * @param {boolean} [options.header=true] when using format: 'csv', set to false to remove the header row
     * @param {boolean} [options.array=false] set to true to always return an array of objects, even if count == 1
     * @param {Field[]} options.fields
     * @return {Promise<Object[]>} The promise resolves to an object if count == 1 or array of objects if count > 1.  Each object represents a record. Keys are the field names.
     */
  generate (options) {
    if (!options || (!options.schema && !options.fields)) throw new Error("Either fields or schema option must be specified");

    this.validateFields(options.fields);

    const url = this.getUrl(options);

    return new Promise((resolve, reject) => {
      axios.post(url, options.fields)
        .then(resp => resolve(resp.data))
        .catch(resp => reject(this.convertError(resp)));
    });
  }

  /**
     * @private
     * @param {Object[]} fields
     */
  validateFields (fields) {
    if (!fields) return;

    if (fields instanceof Array) {
      for (const field of fields) {
        if (!field.name) throw new Error("each field must have a name");
        if (!field.type) throw new Error("each field must have a type");
      }
    } else {
      throw new Error("fields must be an array");
    }
  }

  /**
     * Generates the rest api url
     * @private
     * @return {String}
     */
  getUrl (options) {
    options = Object.assign({ count: 1, format: "json" }, options);
    const protocol = this.secure ? "https" : "http";
    const port = this.port ? `:${this.port}` : "";
    const schema = options.schema ? `&schema=${options.schema}` : "";
    const header = options.header !== undefined ? `&header=${options.header}` : "";
    const array = options.array !== undefined ? `&array=${options.array}` : "";
    if (options.format !== "json" && options.format !== "csv") throw new Error("format must be json or csv");
    return `${protocol}://${this.host}${port}/api/generate.${options.format}?client=node&key=${encodeURIComponent(this.apiKey)}&count=${options.count}${array}${schema}${header}`;
  }

  /**
     * Converts error messages from the mockaroo server to error classes
     * @private
     */
  convertError (response) {
    const error = response.data.error;

    if (error === "Invalid API Key") {
      return new errors.InvalidApiKeyError(response.error);
    } else if (error.match(/limited/)) {
      return new errors.UsageLimitExceededError(response.error);
    } else {
      return new errors.ApiError(error);
    }
  }

  /**
     * Validates that all required options have be specified.
     * @private
     */
  validate () {
    if (!this.apiKey) throw new Error("apiKey is required");
  }
}