From 0abcba8f22f7f0ac65e5d4b2b261f73a6a9d8f46 Mon Sep 17 00:00:00 2001 From: John Shields Date: Thu, 22 Feb 2024 15:40:23 +0000 Subject: [PATCH] =?UTF-8?q?PP-11681=20Remove=20=E2=80=98base.client?= =?UTF-8?q?=E2=80=99=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove ‘base.client’ code as now replaced by calls to ‘axios-base-client’. - Remove associated test. --- .../clients/base-client/base.client.js | 102 ------- .../clients/base-client/base.client.test.js | 253 ------------------ 2 files changed, 355 deletions(-) delete mode 100644 app/services/clients/base-client/base.client.js delete mode 100644 app/services/clients/base-client/base.client.test.js diff --git a/app/services/clients/base-client/base.client.js b/app/services/clients/base-client/base.client.js deleted file mode 100644 index 4b9ca322f3..0000000000 --- a/app/services/clients/base-client/base.client.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict' - -const request = require('request') -const { getRequestCorrelationIDField } = require('../../../utils/request-context') -const joinURL = require('url-join') -const lodash = require('lodash') -const { CORRELATION_HEADER } = require('../../../../config') -const requestLogger = require('../../../utils/request-logger') -const { RESTClientError } = require('../../../errors') - -// Constants -const SUCCESS_CODES = [200, 201, 202, 204, 206] - -// Create request.defaults config -const requestOptions = { - agentOptions: { - keepAlive: true, - maxSockets: process.env.MAX_SOCKETS || 100 - }, - json: true, - maxAttempts: 3, - retryDelay: 5000, - // Adding retry on ECONNRESET as a temporary fix for PP-1727 - retryStrategy: retryStrategy -} - -const client = request.defaults(requestOptions) - -/** - * @param {Null | Object} err - * @param {Object} response - * @param {Object} body - * @return {Boolean} true if the request should be retried - */ -function retryStrategy (err, response, body) { - return process.env.NODE_ENV === 'production' && (err && ['ECONNRESET'].includes(err.code)) -} - -function makeRequest (method, opts) { - return new Promise((resolve, reject) => { - opts.method = method.toUpperCase() - - const loggingContext = { - correlationId: getRequestCorrelationIDField(), - startTime: new Date(), - url: joinURL(lodash.get(opts, 'baseUrl', ''), opts.url), - method: opts.method, - description: opts.description, - service: opts.service, - additionalLoggingFields: opts.additionalLoggingFields - } - - lodash.set(opts, `headers.${CORRELATION_HEADER}`, loggingContext.correlationId) - opts.headers['Content-Type'] = opts.headers['Content-Type'] || 'application/json' - - // Set up post response and error handling method - const transform = opts.transform || false - opts.transform = undefined - - // start request - requestLogger.logRequestStart(loggingContext) - const call = client(opts, (err, response, body) => { - if (err) { - reject(err) - } else if (response && SUCCESS_CODES.includes(response.statusCode)) { - // transform our output if the appropriate function was passed. - body = transform ? transform(body) : body - resolve(body) - } else { - let errors = body && (body.message || body.errors) - if (errors && Array.isArray(errors)) { - errors = errors.join(', ') - } - const message = errors || body || 'Unknown error' - const errorIdentifier = body && body.error_identifier - const reason = body && body.reason - const err = new RESTClientError(message, opts.service, response.statusCode, errorIdentifier, reason) - reject(err) - } - }) - // Add event listeners for logging - call.on('error', err => { - requestLogger.logRequestEnd(loggingContext) - requestLogger.logRequestError(loggingContext, err) - }) - call.on('response', response => { - requestLogger.logRequestEnd(loggingContext, response) - if (!(response && SUCCESS_CODES.includes(response.statusCode))) { - requestLogger.logRequestFailure(loggingContext, response) - } - }) - return call - }) -} - -module.exports = { - get: opts => makeRequest('get', opts), - post: opts => makeRequest('post', opts), - put: opts => makeRequest('put', opts), - patch: opts => makeRequest('patch', opts), - delete: opts => makeRequest('delete', opts) -} diff --git a/app/services/clients/base-client/base.client.test.js b/app/services/clients/base-client/base.client.test.js deleted file mode 100644 index 30a09f4f0a..0000000000 --- a/app/services/clients/base-client/base.client.test.js +++ /dev/null @@ -1,253 +0,0 @@ -'use strict' - -const chai = require('chai') -const chaiAsPromised = require('chai-as-promised') -const sinon = require('sinon') -const proxyquire = require('proxyquire') -const events = require('events') -const { EventEmitter } = require('events') -const util = require('util') -const { RESTClientError } = require('../../../errors') - -const expect = chai.expect -chai.use(chaiAsPromised) - -const correlationId = 'a-correlation-id' -const requestLogger = { - logRequestStart: sinon.spy(), - logRequestEnd: sinon.spy(), - logRequestFailure: sinon.spy(), - logRequestError: sinon.spy() -} -let requestOptions - -function RequestSuccessStub (response, responseBody) { - const self = this - EventEmitter.call(self) - return function (options, callback) { - setTimeout(() => { - // Emit a response event which is handled in the client to log the response - self.emit('response', response) - - // Record the request options so we can do assertions on them in tests - requestOptions = options - - // Execute callback to simulate the response from the service - callback(null, response, responseBody) - }, 100) - return self - } -} - -function RequestErrorStub () { - const self = this - events.EventEmitter.call(self) - return function (options, callback) { - setTimeout(() => { - // Emit an error event which is handled in the client to log the request error - self.emit('error', new Error('something simply dreadful happened')) - callback(new Error('something simply dreadful happened')) - }, 100) - return self - } -} - -// Wire the EventEmitter into the stubs to mimic the behaviour of the request library -util.inherits(RequestSuccessStub, EventEmitter) -util.inherits(RequestErrorStub, EventEmitter) - -function getBaseClientWithSuccessStub (response, responseBody) { - return proxyquire('../../../../app/services/clients/base-client/base.client', { - '../../../utils/request-logger': requestLogger, - '../../../utils/request-context': { - getRequestCorrelationIDField: () => { return correlationId } - }, - 'request': new RequestSuccessStub(response, responseBody) - }) -} - -function getBaseClientWithErrorStub () { - return proxyquire('../../../../app/services/clients/base-client/base.client', { - '../../../utils/request-logger': requestLogger, - '../../../utils/request-context': { - getRequestCorrelationIDField: () => { return correlationId } - }, - 'request': new RequestErrorStub() - }) -} - -describe('Base client', () => { - beforeEach(() => { - requestLogger.logRequestStart.resetHistory() - requestLogger.logRequestEnd.resetHistory() - requestLogger.logRequestFailure.resetHistory() - requestLogger.logRequestError.resetHistory() - requestOptions = null - }) - - describe('Request returns a success response', () => { - const response = { statusCode: 200 } - const responseBody = { result: 'success' } - const baseClient = getBaseClientWithSuccessStub(response, responseBody) - - it('should resolve with the response body', () => { - return expect(baseClient.get({ url: 'http://example.com/' })).to.be.fulfilled.then(resolved => { - expect(resolved).to.have.property('result', 'success') - - expect(requestOptions).to.have.property('headers') - expect(requestOptions.headers).to.deep.equal({ - 'x-request-id': correlationId, - 'Content-Type': 'application/json' - }) - expect(requestOptions).to.have.property('method') - expect(requestOptions.method).to.equal('GET') - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(false) - expect(requestLogger.logRequestFailure.called).to.equal(false) - }) - }) - }) - - describe('Request returns non-success response', () => { - describe('The request returns a non-success response with text content type', () => { - const response = { statusCode: 404 } - const responseBody = 'not found' - const baseClient = getBaseClientWithSuccessStub(response, responseBody) - - it('should reject with an error', () => { - return expect(baseClient.get({ url: 'http://example.com/' })) - .to.be.rejected.then(error => { - expect(error.constructor).to.equal(RESTClientError) - expect(error.message).to.equal('not found') - expect(error.errorCode).to.equal(404) - expect(error.errorIdentifier).to.equal(undefined) - expect(error.reason).to.equal(undefined) - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(false) - expect(requestLogger.logRequestFailure.called).to.equal(true) - }) - }) - }) - - describe('The request returns a non-success response with JSON content type containing an "errors" field of type array', () => { - const response = { statusCode: 404 } - const responseBody = { - errors: ['First error', 'Second error'], - error_identifier: 'GENERIC', - reason: 'a reason' - } - const baseClient = getBaseClientWithSuccessStub(response, responseBody) - - it('should reject with an error', () => { - return expect(baseClient.get({ url: 'http://example.com/' })) - .to.be.rejected.then(error => { - expect(error.constructor).to.equal(RESTClientError) - expect(error.message).to.equal('First error, Second error') - expect(error.errorCode).to.equal(404) - expect(error.errorIdentifier).to.equal('GENERIC') - expect(error.reason).to.equal('a reason') - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(false) - expect(requestLogger.logRequestFailure.called).to.equal(true) - }) - }) - }) - - describe('The request returns a non-success response with JSON content type containing a "message" field of type array', () => { - const response = { statusCode: 404 } - const responseBody = { - message: ['First error', 'Second error'], - error_identifier: 'GENERIC', - reason: 'a reason' - } - const baseClient = getBaseClientWithSuccessStub(response, responseBody) - - it('should reject with an error', () => { - return expect(baseClient.get({ url: 'http://example.com/' })) - .to.be.rejected.then(error => { - expect(error.constructor).to.equal(RESTClientError) - expect(error.message).to.equal('First error, Second error') - expect(error.errorCode).to.equal(404) - expect(error.errorIdentifier).to.equal('GENERIC') - expect(error.reason).to.equal('a reason') - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(false) - expect(requestLogger.logRequestFailure.called).to.equal(true) - }) - }) - }) - - describe('The request returns a non-success response with JSON content type containing a "message" field of type string', () => { - const response = { statusCode: 404 } - const responseBody = { - message: 'The only error', - error_identifier: 'GENERIC', - reason: 'a reason' - } - const baseClient = getBaseClientWithSuccessStub(response, responseBody) - - it('should reject with an error', () => { - return expect(baseClient.get({ url: 'http://example.com/' })) - .to.be.rejected.then(error => { - expect(error.constructor).to.equal(RESTClientError) - expect(error.message).to.equal('The only error') - expect(error.errorCode).to.equal(404) - expect(error.errorIdentifier).to.equal('GENERIC') - expect(error.reason).to.equal('a reason') - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(false) - expect(requestLogger.logRequestFailure.called).to.equal(true) - }) - }) - }) - - describe('The request returns a non-success response with no body', () => { - const response = { statusCode: 404 } - const baseClient = getBaseClientWithSuccessStub(response, null) - - it('should reject with an error', () => { - return expect(baseClient.get({ url: 'http://example.com/' })) - .to.be.rejected.then(error => { - expect(error.constructor).to.equal(RESTClientError) - expect(error.message).to.equal('Unknown error') - expect(error.errorCode).to.equal(404) - expect(error.errorIdentifier).to.equal(null) - expect(error.reason).to.equal(null) - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(false) - expect(requestLogger.logRequestFailure.called).to.equal(true) - }) - }) - }) - }) - - describe('There is an expected error making a request', () => { - const baseClient = getBaseClientWithErrorStub() - - it('should reject with a generic error', () => { - return expect(baseClient.get({ url: 'http://example.com/' })) - .to.be.rejected.then(error => { - expect(error.constructor).to.equal(Error) - expect(error.message).to.equal('something simply dreadful happened') - expect(error.errorCode).to.equal(undefined) - - expect(requestLogger.logRequestStart.called).to.equal(true) - expect(requestLogger.logRequestEnd.called).to.equal(true) - expect(requestLogger.logRequestError.called).to.equal(true) - expect(requestLogger.logRequestFailure.called).to.equal(false) - }) - }) - }) -})