lib/request.js

const { clone } = require('../utils/helpers');
const current_API_version_endpoint = 3;
const allowableVersions = [2, 3];
const is_nodejs = typeof module !== 'undefined' && module.exports;

/**
 * @description Make a request using the SkyCiv API
 * @param {object} apiObject A SkyCiv API Object
 * @param {function} callback The function to run after the request. Receives a parsed response.
 * @param {Object} options Additional options
 * @param {2 | 3} options.version The API version to use. Defaults to 3.
 * @param {"http" | "https"} options.http_or_https Whethere the request should use http or https. Defaults to https.
 */
function request(apiObject, callback, options = {}) {
	let reqObject = clone(apiObject);

	// Convert ApiObject class to JSON - Can't use instanceof as it will create a circular dependency.
	if (apiObject.__proto__.constructor.name === 'ApiObject') {
		reqObject = apiObject.get();
	}

	//  Input validation
	if (!options) options = {};

	// Check version
	if (!options.version) options.version = current_API_version_endpoint;
	if (!allowableVersions.includes(options.version))
		throw new Error(
			`options.version should be one of the following: ${allowableVersions.join(', ')}`
		);

	// Check transport method
	if (!options.http_or_https) options.http_or_https = 'https';

	// Check if already stringified
	if (typeof reqObject === 'object') {
		reqObject = JSON.stringify(reqObject);
	}

	// FOR NODE.JS
	if (is_nodejs) {
		var req_module;
		var req_port;

		if (options.http_or_https == 'https') {
			req_module = require('https');
			req_port = 8085; // 443;
		} else {
			req_module = require('http');
			req_port = 8086; // 80;
		}

		var req_options = {
			hostname: 'api.skyciv.com',
			port: req_port,
			path: '/v' + options.version + '',
			method: 'POST',
			headers: {
				// these are compulsory for it to work properly
				'Content-Type': 'application/json',
				'Content-Length': Buffer.byteLength(reqObject),
			},
			//timeout: timeout
		};

		var req = req_module.request(req_options, function (res) {
			res.setEncoding('utf8');

			var res_data = '';
			res.on('data', function (chunk) {
				res_data += chunk;
			});

			res.on('end', function () {
				if (!res_data) {
					res_data = JSON.stringify({
						response: {
							status: 1,
							msg:
								'No response was received from the API. Please contact [email protected] for more assistance with this.',
						},
					});
				}

				const parsed_res = JSON.parse(res_data);

				if (callback) {
					callback(parsed_res);
				}
			});
		});

		req.on('error', function (e) {
			console.log('Problem with request: ' + e.message);
		});

		// Send the object as a JSON string
		req.write(reqObject);
		req.end();
	} else {
		// FOR BROWSER
		var req = new XMLHttpRequest();

		req.onreadystatechange = function () {
			if (req.readyState == XMLHttpRequest.DONE) {
				var response_obj;
				try {
					if (req.responseText) {
						response_obj = JSON.parse(req.responseText);
					} else {
						response_obj = {
							response: {
								status: 1,
								msg:
									'No response was received from the API. Please contact [email protected] for more assistance with this.',
							},
						};
					}
				} catch (e) {
					response_obj = {
						response: {
							status: 2,
							msg:
								'There was an issue parsing the response from the API. Please contact [email protected] for more assistance with this.',
						},
					};
				}

				if (typeof response_obj === 'string') {
					response_obj = JSON.parse(response_obj);
				}

				if (callback) {
					callback(response_obj);
				}
			}
		};

		var req_port = '';
		if (options.http_or_https == 'https') {
			req_port = ':8085'; // 443;
		} else {
			req_port = ':8086'; // 80;
		}

		//req.timeout = timeout;
		req.open(
			'POST',
			options.http_or_https + '://api.skyciv.com' + req_port + '/v' + options.version,
			true
		); // true=async
		req.setRequestHeader('Content-type', 'application/json');
		req.send(reqObject);
	}
}

module.exports = request;