const fetch = require('isomorphic-fetch'); const { apiEndpoint } = require('./endpoint'); const logger = require('./logger'); // expected time for API service to respond const RESPONSE_TIMEOUT = 2 * 60 * 1000; const fetcher = (url, options = {}, mode = 'JSON') => { const finalUrl = apiEndpoint + url; logger.info(`Making request to ${finalUrl}`); let timer = null; const timeout = new Promise((resolve) => { timer = setTimeout(() => { logger.error(new Error('connection timeout!')); resolve({ data: {}, headers: {}, statusCode: -1, error: true, message: 'connection timeout!', }); }, RESPONSE_TIMEOUT); }); const service = new Promise((resolve) => { fetch(finalUrl, options) .then((response) => { logger.log(`${response.ok ? 'info' : 'error'}`, `API response status: ${response.status}`); clearTimeout(timer); const statusCode = response.status; const { headers } = response; // redirect should come as 200 with `redirectUrl` attribute in response if (statusCode === 301) logger.warn('API responded with redirect'); const dataPromise = mode === 'JSON' ? response.json() : response.text(); dataPromise .then((data) => { if (statusCode >= 200 && statusCode <= 301) { resolve({ data, headers, statusCode, error: false, message: null, }); } else { logger.error(`${data.error || response.statusText}`); logger.error(`Message: ${data.message || response.statusText}`); resolve({ data, headers, statusCode, error: true, message: data.message || response.statusText, }); } }) .catch((error) => { logger.error(error); resolve({ data: {}, headers, statusCode, error: true, message: error.message, }); }); }) .catch((error) => { clearTimeout(timer); logger.error(error); resolve({ data: {}, headers: {}, statusCode: -1, error: true, message: error.message, }); }); }); return Promise.race([timeout, service]); }; module.exports.fetcher = fetcher;