UNPKG

bccr-indicadores-economicos

Version:

Interfaz para consumo del servicio web de indicadores económicos del Banco Central de Costa Rica (BCCR).

1 lines 20.5 kB
{"version":3,"sources":["../src/util/responseUtil.ts","../src/util/requestUtil.ts","../src/util/validationUtil.ts","../src/BCCRWebService.ts","../src/index.ts"],"sourcesContent":["import { parseString } from \"xml2js\";\nimport { DataPoint } from \"../types/BCCR.types\";\n\nconst BCCR_VALUE_TAG: string = \"NUM_VALOR\";\nconst BCCR_DATE_TAG: string = \"DES_FECHA\";\nconst BCCR_CODE_TAG: string = \"COD_INDICADORINTERNO\";\n\n/**\n * Utilitarian function that fetches the first child node value on XML structured text that matches with a specific tag name.\n * @param response XML structured text.\n * @param tagName Target tag name to fetch.\n */\nconst getSingleValueByTagName = (response: string, tagName: string): string => {\n try {\n return parseXMLStringToJSON(response)[0][tagName][0];\n } catch (e) {\n throw new Error(\n \"Error while extracting value from single indicator data point.\",\n );\n }\n};\n\n/**\n * Utilitarian function that fetches all node values on XML structured text that matches with a specific tag name.\n * @param response XML structured text.\n * @param tagName Target tag name to fetch.\n */\nconst getValuesByTagName = (response: string, tagName: string): any[] => {\n try {\n return parseXMLStringToJSON(response).map((node) => node[tagName][0]);\n } catch (e) {\n throw new Error(\n \"Error while extracting values from indicator data set.\",\n );\n }\n};\n\n/**\n * Utilitarian function that parses an XML formatted string into a JSON.\n * @param XMLString\n */\nexport const parseXMLStringToJSON = (XMLString: string): any[] => {\n // Parse result temp variable.\n let parseResult: any[] = [];\n // First level of parsing. This extract the superficial structure of BCCR XML response.\n parseString(XMLString, (partialErr, partialResult) => {\n if (partialErr) {\n throw new Error(\"Error while parsing BCCR web service response.\");\n }\n // Second level of parsing. This extract the data set.\n parseString(\n partialResult.string[\"_\"],\n (jsonParsedErr, jsonParsedResult) => {\n if (jsonParsedErr) {\n throw new Error(\n \"Error while parsing BCCR web service response.\",\n );\n }\n // Parse result temp variable assignation.\n parseResult =\n jsonParsedResult.Datos_de_INGC011_CAT_INDICADORECONOMIC\n .INGC011_CAT_INDICADORECONOMIC;\n },\n );\n });\n return parseResult;\n};\n\n/**\n * Utilitarian function that counts the number of valid data points in XML structured text.\n * @param response XML structured text.\n */\nexport const getResponseLength = (response: string): number => {\n try {\n return parseXMLStringToJSON(response).length;\n } catch (e) {\n throw new Error(\n \"Empty response from BCCR web service. Validate indicator code, publication periodicity and indicator structure (compound or simple).\",\n );\n }\n};\n\n/**\n * Utilitarian function that extract a data point from a XML formatted response.\n * @param dataPoint XML structured text containing target data point.\n */\nconst getDataPoint = (dataPoint: string): DataPoint => {\n return {\n code: getSingleValueByTagName(dataPoint, BCCR_CODE_TAG),\n date: getSingleValueByTagName(dataPoint, BCCR_DATE_TAG),\n value: parseFloat(getSingleValueByTagName(dataPoint, BCCR_VALUE_TAG)),\n };\n};\n\n/**\n * Utilitarian function that extract a data set from a XML formatted response.\n * @param dataSet XML structured text containing target data set.\n */\nconst getDataSet = (dataSet: string): DataPoint[] => {\n // Definition of temporal result data structure.\n let targetDataSet = [];\n\n // Retrieval target of values\n const codes = getValuesByTagName(dataSet, BCCR_CODE_TAG);\n const dates = getValuesByTagName(dataSet, BCCR_DATE_TAG);\n const values = getValuesByTagName(dataSet, BCCR_VALUE_TAG);\n\n // Collapse of retrieved target values into list of objects.\n for (let i = 0; i < getResponseLength(dataSet); i++) {\n targetDataSet.push({\n code: codes[i],\n date: dates[i],\n value: parseFloat(values[i]),\n });\n }\n\n return targetDataSet;\n};\n\n/**\n * Utilitarian function for data extraction from BCCR web service response. This function handle single and multiple value responses.\n * @param res BCCR web service response.\n */\nexport const getResponseData = (\n res: Response,\n): Promise<DataPoint | DataPoint[]> => {\n return new Promise((resolve, reject) => {\n res.text()\n .then((txt) => {\n // Check response length to select data handle method.\n if (getResponseLength(txt) === 1) {\n resolve(getDataPoint(txt));\n } else {\n resolve(getDataSet(txt));\n }\n })\n .catch((e) => {\n reject(e);\n });\n });\n};\n","import { getResponseLength } from \"./responseUtil\";\n\n/**\n * Utilitarian function that fetches BCCR web service.\n * @param code Unique code corresponding to an BCCR financial indicator.\n * @param startDate Request range start date.\n * @param endDate Request range end date.\n * @param email Email registered before BCCR for web service.\n * @param token Access token given by BCCR for web service.\n */\nexport const fetchBCCRWebService = (\n code: string,\n startDate: string,\n endDate: string,\n email: string,\n token: string,\n): Promise<Response> => {\n return new Promise(async (resolve, reject) => {\n // Request parameters string construction.\n const params: string = `/Indicadores/Suscripciones/WS/wsindicadoreseconomicos.asmx/ObtenerIndicadoresEconomicosXML?Indicador=${code}&FechaInicio=${startDate}&FechaFinal=${endDate}&Nombre=N&SubNiveles=S&CorreoElectronico=${email}&Token=${token}`;\n try {\n resolve(await fetch(\"https://gee.bccr.fi.cr\" + params));\n } catch (e) {\n reject(e);\n }\n });\n};\n\n/**\n * Utilitarian recursive function that fetches BCCR web service looking for the date of current the current value for a given indicator code. Latest value available.\n * @param code Unique code corresponding to an BCCR financial indicator.\n * @param targetDate Changing date parameter through recursion. This parameter is decreased util valid date is found.\n * @param email Email registered before BCCR for web service.\n * @param token Access token given by BCCR for web service.\n */\nexport const fetchCurrentValueDate = (\n code: string,\n email: string,\n token: string,\n targetDate: Date = new Date(),\n): Promise<Date> => {\n return new Promise((resolve) => {\n const formattedTargetDate: string = targetDate.toLocaleDateString(\n \"es-ES\",\n {\n timeZone: \"UTC\",\n },\n );\n // BCCR web service request.\n fetchBCCRWebService(\n code,\n formattedTargetDate,\n formattedTargetDate,\n email,\n token,\n )\n .then((res) => res.text())\n .then((txt) => {\n try{\n // If response length is successfully retrieve an available date has been reached.\n getResponseLength(txt)\n resolve(targetDate);\n }catch{\n // Parameter date decrement.\n targetDate.setDate(targetDate.getDate() - 1);\n // Recursive call.\n resolve(\n fetchCurrentValueDate(code, email, token, targetDate),\n );\n\n }\n });\n });\n};\n","import { isDate } from \"node:util/types\";\nimport { fetchBCCRWebService } from \"./requestUtil\";\nimport { parseXMLStringToJSON } from \"./responseUtil\";\n\nconst BCCR_ERROR_TAG = \"Error\";\n\n/**\n * Utilitarian procedure that validates credentials given by the user with a dummy request to BCCR web service.\n * @param email Email registered before BCCR for web service.\n * @param token Access token given by BCCR for web service.\n */\nexport const validateCredentials = (email: string, token: string): void => {\n // Target dummy data definition and formatting.\n const formattedDummyDate: string = new Date().toLocaleDateString(\"es-ES\", {\n timeZone: \"UTC\",\n });\n // Dummy request and checks if error tag is present in the response.\n fetchBCCRWebService(\n \"318\",\n formattedDummyDate,\n formattedDummyDate,\n email,\n token,\n )\n .then((response) => response.text())\n .then((txt) => {\n try {\n parseXMLStringToJSON(txt);\n } catch {\n throw new Error(\n \"Bad credentials. Email or token (or both) rejected by BCCR web service.\",\n );\n }\n });\n};\n\n/**\n * Utilitarian function that checks BCCRWebService constructor method parameters integrity.\n * @param email Email registered before BCCR for web service.\n * @param token Access token given by BCCR for web service.\n */\nexport const validateConstructorParameters = (\n email: string,\n token: string,\n): void => {\n if (!email.length) {\n throw new Error(\n \"Found empty string as email constructor parameter. This parameter must be an string containing a valid email address.\",\n );\n }\n if (!token.length) {\n throw new Error(\n \"Found empty string as token constructor parameter. This parameter must be an string containing an alphanumerical value.\",\n );\n }\n};\n\n/**\n * Utilitarian function that checks BCCRWebService request method parameters integrity.\n * @param code Unique code corresponding to an BCCR financial indicator.\n * @param startDate Request range start date.\n * @param endDate Request range end date.\n */\nexport const validateRequestParameters = (\n code: string,\n startDate: Date,\n endDate: Date,\n): void => {\n if (!code.length) {\n throw new Error(\n \"Found empty string as indicator code parameter. This parameter must be an string containing a numerical value.\",\n );\n }\n if (isNaN(Number(code))) {\n throw new Error(\n \"Indicator code parameter must be an string containing a numerical value.\",\n );\n }\n if (startDate && !isDate(startDate)) {\n throw new Error(\n \"startDate parameter must be a Date object instance.\",\n );\n }\n if (endDate && !isDate(endDate)) {\n throw new Error(\n \"endDate parameter must be a Date object instance.\",\n );\n }\n if (startDate > new Date() || endDate > new Date()) {\n throw new Error(\n \"endDate parameter nor startDate parameter can be dates in the future.\",\n );\n }\n if (startDate > endDate) {\n throw new Error(\"endDate parameter must a date after startDate parameter date.\");\n }\n};\n","import { getResponseData } from \"./util/responseUtil\";\nimport { DataPoint } from \"./types/BCCR.types\";\nimport {\n validateConstructorParameters,\n validateCredentials,\n validateRequestParameters,\n} from \"./util/validationUtil\";\nimport { fetchBCCRWebService, fetchCurrentValueDate } from \"./util/requestUtil\";\n\nmodule.exports = class BCCRWebService {\n // Email registered before BCCR for web service.\n private readonly email: string;\n // Access token given by BCCR for web service.\n private readonly token: string;\n\n /**\n * Constructor method for BCCR web service consumption class.\n * @param email Email registered before BCCR for web service.\n * @param token Access token given by BCCR for web service.\n */\n constructor(email: string, token: string) {\n validateConstructorParameters(email, token);\n validateCredentials(email, token);\n this.email = email;\n this.token = token;\n }\n\n /**\n * Method that manages BCCR indicator web service fetch logic.\n * @param code Unique code corresponding to an BCCR financial indicator.\n * @param startDate Request range start date.\n * @param [endDate = startDate] Optional request range end date. If not provided the startDate parameter value is set as default.\n */\n request = (\n code: string,\n startDate: Date,\n endDate: Date = startDate\n ): Promise<DataPoint | DataPoint[]> => {\n validateRequestParameters(code, startDate, endDate);\n return new Promise(async (resolve, reject) => {\n // Date object conversion into request compatible format.\n let formattedStartDate: string;\n let formattedEndDate: string;\n // Control sequence structure that checks if startDate and endDate provided\n if (!(startDate || endDate)) {\n // When startDate and endDate are NOT provided target date is fetched, its result is formatted into locale string and assigned to corresponding variables.\n const formattedTargetDate = (\n await fetchCurrentValueDate(\n code,\n this.email,\n this.token,\n )\n ).toLocaleDateString(\"es-ES\", { timeZone: \"America/Costa_Rica\" });\n formattedStartDate = formattedEndDate = formattedTargetDate;\n } else {\n // When startDate and endDate ARE provided values are formatted into locale string and assigned to corresponding variables.\n formattedStartDate = startDate.toLocaleDateString(\"es-ES\", {\n timeZone: \"America/Costa_Rica\",\n });\n formattedEndDate = endDate.toLocaleDateString(\"es-ES\", {\n timeZone: \"America/Costa_Rica\",\n });\n }\n\n // BCCR web service data retrieval and response formatting.\n fetchBCCRWebService(\n code,\n formattedStartDate,\n formattedEndDate,\n this.email,\n this.token,\n )\n .then((response) => getResponseData(response))\n .then((data) => resolve(data))\n .catch((e) => reject(e));\n });\n };\n};\n","const BCCRWebService = require(\"./BCCRWebService\");\n\nconst bccrWS = new BCCRWebService(\"andresmonterog@hotmail.com\", \"MOHDSTRRNE\");\n\nconst test = async () => {\n// Fecha que de inicio del rango que se desea recuperar.\nconst startDate = new Date(2024, 0, 1);\n// Fecha que de fin del rango que se desea recuperar.\nconst endDate = new Date(2024, 0, 5);\n// Ejemplo con código 318: Tipo de cambio venta dólar/colón.\nconst rangedColonDollarSellPrice = await bccrWS.request(\n \"318\",\n startDate,\n endDate,\n);\n console.log(rangedColonDollarSellPrice);\n}\n\ntest()\n\n// module.exports = require(\"./BCCRWebService\");\n"],"mappings":"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","names":[]}