UNPKG

coindesk

Version:

Client for retrieving Bitcoin information from Coindesk API service

244 lines (224 loc) 8.79 kB
/* * Coindesk API client utilities. */ const fs = require('fs'); const { getLogger } = require('../logger/service'); const { CoindeskAPIClientError } = require('../errors'); const { CoindeskAPIHttpRequestError } = require('../errors'); const { CoindeskAPIHttpResponseError } = require('../errors'); const schema = require('./schemas'); const settings = require('../settings'); const supportedCurrencies = require('../currencies.json').SUPPORTED_CURRENCIES; const logger = getLogger(__filename); let validateDataType = (dataType) => { if (!settings.VALID_DATA_TYPES.includes(dataType)) { const message = `Data type must be ${ settings.VALID_DATA_TYPES.join(', ') }.`; logger.error(`[CoindeskAPIClient] Data type error: ${ message }`); throw new CoindeskAPIClientError(message); } return dataType; }; let validateParams = (dataType, params) => { if (dataType === settings.API_CURRENTPRICE_DATA_TYPE) { for (let param in params) { if (!settings.VALID_CURRENTPRICE_PARAMS.includes(param)) { const message = `Unvalid param ${ param } for ${ dataType } data type.`; logger.error(`[CoindeskAPIClient] Param error: ${ message }`); throw new CoindeskAPIClientError(message); } } if (params.hasOwnProperty(settings.CURRENCY_PARAM)) { validateCurrency(params[settings.CURRENCY_PARAM]); } } else if (dataType === settings.API_HISTORICAL_DATA_TYPE) { for (let param in params) { if (!settings.VALID_HISTORICAL_PARAMS.includes(param)) { const message = `Unvalid param ${ param } for ${ dataType } data type.`; logger.error(`[CoindeskAPIClient] Param error: ${ message }`); throw new CoindeskAPIClientError(message); } } if (params.hasOwnProperty(settings.INDEX_PARAM)) { validateIndex(params[settings.INDEX_PARAM]); } if (params.hasOwnProperty(settings.CURRENCY_PARAM)) { validateCurrency(params[settings.CURRENCY_PARAM]); } if (params.hasOwnProperty(settings.START_PARAM)) { validateDate(params[settings.START_PARAM]); } if (params.hasOwnProperty(settings.END_PARAM)) { validateDate(params[settings.END_PARAM]); } if (params.hasOwnProperty(settings.FOR_PARAM)) { validateFor(params[settings.FOR_PARAM]); } } else { const message = `Unable to validate params for data type ${ dataType }.`; logger.error(`[CoindeskAPIClient] Data type error: ${ message }`); throw new CoindeskAPIClientError(message); } return params; }; let validateIndex = (index) => { if (!settings.VALID_INDEX.includes(index)) { const message = `'Index' must be ${ settings.VALID_INDEX.join(', ') }.`; logger.error(`[CoindeskAPIClient] Index error: ${ message }`); throw new CoindeskAPIClientError(message); } }; let validateCurrency = (currency) => { const currencies = supportedCurrencies.map(currency => currency.currency); if (currency !== null && !currencies.includes(currency)) { const message = `Unvalid provided currency ${ currency }.`; logger.error(`[CoindeskAPIClient] Currency error: ${ message }`); throw new CoindeskAPIClientError(message); } }; let validateDate = (params, flag) => { const date = params[flag]; const match = date.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/); if (match) { try { const parsedDate = new Date(match[1], match[2] - 1, match[3]).toISOString(); params[flag] = parsedDate.slice(0, parsedDate.indexOf('T')); } catch (err) { const message = err.message; logger.error(`[CoindeskAPIClient] Date error: ${ message }.`); throw new CoindeskAPIClientError(message); } } else { const message = `${ flag } must fullfill the pattern YYYY-MM-DD.`; logger.error(`[CoindeskAPIClient] Date error: ${ message }`); throw new CoindeskAPIClientError(message); } }; let validateFor = (forParam) => { if (!settings.VALID_FOR.includes(forParam)) { const message = `For must be ${ settings.VALID_FOR.join(', ') }.`; logger.error(`[CoindeskAPIClient] For error: ${ message }`); throw new CoindeskAPIClientError(message); } }; let validateRetries = (retries) => { if (typeof retries !== 'number' || !Number.isInteger(retries)) { const message = `Retries type ${ typeof retries } must be integer number.`; logger.error(`[CoindeskAPIHttpRequest] Retries error: ${ message }`); throw new CoindeskAPIHttpRequestError(message); } const maxRetries = parseInt(Math.min(retries, settings.REQUEST_MAX_RETRIES)); if (maxRetries < retries) { logger.warn(`[CoindeskAPIHttpRequest] Request max retries: ${ maxRetries }.`); } return maxRetries; }; let validateRedirects = (redirects) => { if (typeof redirects !== 'number' || !Number.isInteger(redirects)) { const message = `Redirects type ${ typeof redirects } must be integer number.`; logger.error(`[CoindeskAPIHttpRequest] Redirects error: ${ message }`); throw new CoindeskAPIHttpRequestError(message); } const maxRedirects = parseInt(Math.min(redirects, settings.REQUEST_MAX_REDIRECTS)); if (maxRedirects < redirects) { logger.warn(`[CoindeskAPIHttpRequest] Request max redirects: ${ maxRedirects }.`); } return maxRedirects; }; let validateTimeout = (timeout) => { if (typeof timeout !== 'number' || !Number.isInteger(timeout)) { const message = `Timeout type ${ typeof timeout } must be integer number.`; logger.error(`[CoindeskAPIHttpRequest] Timeout error: ${ message }`); throw new CoindeskAPIHttpRequestError(message); } const maxTimeout = parseInt(Math.min(timeout, settings.REQUEST_MAX_TIMEOUT)); if (maxTimeout < timeout) { logger.warn(`[CoindeskAPIHttpRequest] Request max timeout: ${ maxTimeout }.`); } return maxTimeout; }; let validateBackoff = (backoff) => { if (typeof backoff !== 'boolean') { const message = `Backoff type ${ typeof backoff } must be 'boolean'.`; logger.error(`[CoindeskAPIHttpRequest] Backoff error: ${ message }`); throw new CoindeskAPIHttpRequestError(message); } }; let validateUrl = (url) => { const match = url.match(/(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/); if (!match) { const message = `${ url } is not a valid pattern for an url.`; logger.error(`[CoindeskAPIClient] URL error: ${ message }`); throw new CoindeskAPIClientError(message); } }; let validateSupportedCurrencies = async (currencies) => { const validCurrencies = new Set(currencies.map(currency => currency.currency)); const allowedCurrencies = new Set(supportedCurrencies.map(currency => currency.currency)); for (let currency of validCurrencies) { if (!allowedCurrencies.has(currency)) { const message = `Missing currency ${ currency } in settings.`; logger.warn(`[CoindeskAPIClient] Currency error: ${ message }`); return await updateCurrenciesSettings(currencies); } } }; let readFile = (path) => { return new Promise((resolve, reject) => { fs.readFile(path, (err, data) => { if (err) reject(err); resolve(data); }); }); }; let writeFile = (path, data) => { return new Promise((resolve, reject) => { fs.writeFile(path, data, (err) => { if (err) reject(err); resolve(data); }); }); }; let updateCurrenciesSettings = async (currencies) => { let file; try { file = await readFile('../currencies.json'); } catch (err) { const message = `Unable to read settings file - ${ err.message }.`; logger.error(`[CoindeskAPIClient] File error: ${ message }`); throw new CoindeskAPIClientError(message); } const currenciesObj = JSON.parse(file); currenciesObj.SUPPORTED_CURRENCIES = currencies; const currenciesJSON = JSON.stringify(currenciesObj); try { await writeFile('../currencies.json', currenciesJSON); } catch (err) { const message = `Unable to write settings file - ${ err.message }.`; logger.error(`[CoindeskAPIClient] File error: ${ message }`); throw new CoindeskAPIClientError(message); } }; let getResponseSchema = (dataType, currency) => { switch (dataType) { case settings.API_CURRENTPRICE_DATA_TYPE: if (currency === null) return schema.currentpriceSchema; return schema.currentpriceCurrencySchema; case settings.API_HISTORICAL_DATA_TYPE: return schema.historicalSchema; default: message = `Schema not found for data type ${ dataType } and currency ${ currency }.`; logger.error(`[CoindeskAPIHttpResponse] Schema error: ${ message }`); throw new CoindeskAPIHttpResponseError(message); } }; module.exports = { validateDataType, validateParams, validateRetries, validateRedirects, validateTimeout, validateBackoff, validateUrl, validateSupportedCurrencies, getResponseSchema };