UNPKG

@ministryofjustice/hmpps-digital-prison-reporting-frontend

Version:

The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.

189 lines (184 loc) 7.27 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var superagent = require('superagent'); var Agent = require('agentkeepalive'); var http = require('http'); var https = require('https'); var url = require('url'); var stream = require('stream'); var logger = require('../utils/logger.js'); var sanitisedError = require('../utils/sanitisedError.js'); class RestClient { name; config; agent; constructor(name, config) { this.name = name; this.config = config; this.agent = config.url.startsWith('https') ? new Agent.HttpsAgent(config.agent) : new Agent(config.agent); } apiUrl() { return this.config.url; } timeoutConfig() { return this.config.agent.timeout; } async get(request) { return this.getWithHeaders(request).then(result => result.data); } async getStream({ path = '', query = {}, headers = {}, token }, res) { const url$1 = new url.URL(`${this.apiUrl()}${path}`); Object.entries(query).forEach(([key, value]) => { if (value === undefined) return; if (Array.isArray(value)) { value.forEach(v => url$1.searchParams.append(key, String(v))); } else { url$1.searchParams.append(key, String(value)); } }); const client = url$1.protocol === 'https:' ? https : http; const req = client.request(url$1, { method: 'GET', headers: { ...headers, Authorization: token ? `Bearer ${token}` : undefined, }, agent: this.agent, }, upstream => { // Forward status res.status(upstream.statusCode || 500); // Forward headers Object.entries(upstream.headers).forEach(([key, value]) => { if (value !== undefined) { res.setHeader(key, value); } }); res.flushHeaders(); res.on('close', () => { req.destroy(); }); stream.pipeline(upstream, res, err => { if (err) { res.destroy(err); } }); }); req.setTimeout(this.timeoutConfig(), () => { req.destroy(new Error('Upstream request timed out.')); }); req.on('error', err => { logger.default.warn({ err }, `Error streaming from ${this.name}, path: '${path}'`); if (!res.headersSent) { res.status(502).end('Download request failed'); } else { res.destroy(err); } }); req.end(); } async requestWithBody(method, { path, query = {}, headers = {}, responseType = '', data = {}, raw = false, retry = false }, token) { logger.default.info(`${this.name} ${method.toUpperCase()}: ${path}`); logger.default.info(`info about request: ${method} | ${path} | ${JSON.stringify(data)} | ${JSON.stringify(query)}`); try { const result = await superagent[method](`${this.apiUrl()}${path}`) .query(query) .send(data) .agent(this.agent) .retry(2, err => { if (retry === false) { return false; } if (err) logger.default.info(`Retry handler found API error with ${err.code} ${err.message}`); return undefined; // retry handler only for logging retries, not to influence retry logic }) .auth(token, { type: 'bearer' }) .set(headers) .responseType(responseType) .timeout(this.timeoutConfig()); return raw ? result : result.body; } catch (error) { if (!(error instanceof Error)) { throw error; } const sanitisedError$1 = sanitisedError.default(error); logger.default.warn({ ...sanitisedError$1 }, `Error calling ${this.name}, path: '${path}', verb: '${method.toUpperCase()}'`); throw sanitisedError$1; } } async post(request, token) { return this.requestWithBody('post', request, token); } async getWithHeaders({ path = '', query = {}, headers = {}, responseType = '', raw = false, token, }) { const loggerData = { path: `${this.config.url}${path}`, ...(Object.keys(query).length && { query }), }; logger.default.info(`${this.name}: ${JSON.stringify(loggerData)}`); try { const result = await superagent .get(`${this.apiUrl()}${path}`) .agent(this.agent) .retry(2, err => { if (err) logger.default.info(`Retry handler found API error with ${err.code} ${err.message}`); return undefined; // retry handler only for logging retries, not to influence retry logic }) .query(query) .auth(token, { type: 'bearer' }) .set(headers) .responseType(responseType) .timeout(this.timeoutConfig()); return { data: raw ? result : result.body, headers: result.headers, }; } catch (error) { const sanitisedError$1 = sanitisedError.default(error); logger.default.warn({ ...sanitisedError$1, query }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`); throw sanitisedError$1; } } async deleteWithHeaders({ path = '', query = {}, headers = {}, responseType = '', raw = false, token, }) { const loggerData = { path: `${this.config.url}${path}`, query, }; logger.default.info(`${this.name}: ${JSON.stringify(loggerData)}`); try { const result = await superagent .delete(`${this.apiUrl()}${path}`) .agent(this.agent) .retry(2, err => { if (err) logger.default.info(`Retry handler found API error with ${err.code} ${err.message}`); return undefined; // retry handler only for logging retries, not to influence retry logic }) .query(query) .auth(token, { type: 'bearer' }) .set(headers) .responseType(responseType) .timeout(this.timeoutConfig()); return { data: raw ? result : result.body, headers: result.headers, }; } catch (error) { const sanitisedError$1 = sanitisedError.default(error); logger.default.warn({ ...sanitisedError$1, query }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`); throw sanitisedError$1; } } async delete(request) { return this.deleteWithHeaders(request).then(result => result.data); } } exports.RestClient = RestClient; exports.default = RestClient; //# sourceMappingURL=restClient.js.map