From 2b1c1ec26127ac575ad61851cb454e3198cd771b Mon Sep 17 00:00:00 2001 From: Andrew Hynes Date: Wed, 26 May 2021 10:34:07 -0400 Subject: [PATCH] feat: add `BaseService.constructServiceURL` method --- lib/base-service.ts | 44 ++++++++++++++++++++++++++ test/unit/parameterized-url.test.js | 49 +++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 test/unit/parameterized-url.test.js diff --git a/lib/base-service.ts b/lib/base-service.ts index c23afb549..c2d2090c4 100644 --- a/lib/base-service.ts +++ b/lib/base-service.ts @@ -61,6 +61,50 @@ export class BaseService { static DEFAULT_SERVICE_NAME: string; + /** + * Constructs a service URL by formatting a parameterized URL. + * + * @param {string} parameterizedUrl URL that contains variable placeholders, e.g. '{scheme}://ibm.com'. + * @param {Map} defaultUrlVariables Map from variable names to default values. + * Each variable in the parameterized URL must have a default value specified in this map. + * @param {Map} providedUrlVariables Map from variable names to desired values. + * If a variable is not provided in this map, + * the default variable value will be used instead. + * @returns {string} The formatted URL with all variable placeholders replaced by values. + */ + static constructServiceURL( + parameterizedUrl: string, + defaultUrlVariables: Map, + providedUrlVariables: Map | null + ): string { + // If null was passed, we set the variables to an empty map. + // This results in all default variable values being used. + if (providedUrlVariables === null) { + providedUrlVariables = new Map(); + } + + // Verify the provided variable names. + providedUrlVariables.forEach((_, name) => { + if (!defaultUrlVariables.has(name)) { + throw new Error(`'${name}' is an invalid variable name. + Valid variable names: [${Array.from(defaultUrlVariables.keys()).sort()}].`); + } + }); + + // Format the URL with provided or default variable values. + let formattedUrl = parameterizedUrl; + + defaultUrlVariables.forEach((defaultValue, name) => { + // Use the default variable value if none was provided. + const providedValue = providedUrlVariables.get(name); + const formatValue = providedValue !== undefined ? providedValue : defaultValue; + + formattedUrl = formattedUrl.replace(`{${name}}`, formatValue); + }); + + return formattedUrl; + } + protected baseOptions: BaseServiceOptions; private authenticator: AuthenticatorInterface; diff --git a/test/unit/parameterized-url.test.js b/test/unit/parameterized-url.test.js new file mode 100644 index 000000000..3eb6015ff --- /dev/null +++ b/test/unit/parameterized-url.test.js @@ -0,0 +1,49 @@ +const { BaseService } = require('../../dist/lib/base-service'); + +const parameterizedUrl = '{scheme}://{domain}:{port}'; +const defaultUrlVariables = new Map([ + ['scheme', 'http'], + ['domain', 'ibm.com'], + ['port', '9300'], +]); + +describe('constructServiceURL', () => { + it('should use default variable values when null is passed', () => { + expect(BaseService.constructServiceURL(parameterizedUrl, defaultUrlVariables, null)).toBe( + 'http://ibm.com:9300' + ); + }); + + it('should use the values provided and defaults for the rest', () => { + const providedUrlVariables = new Map([ + ['scheme', 'https'], + ['port', '22'], + ]); + + expect( + BaseService.constructServiceURL(parameterizedUrl, defaultUrlVariables, providedUrlVariables) + ).toBe('https://ibm.com:22'); + }); + + it('should use all provided values', () => { + const providedUrlVariables = new Map([ + ['scheme', 'https'], + ['domain', 'google.com'], + ['port', '22'], + ]); + + expect( + BaseService.constructServiceURL(parameterizedUrl, defaultUrlVariables, providedUrlVariables) + ).toBe('https://google.com:22'); + }); + + it('should throw an error if a provided variable name is wrong', () => { + const providedUrlVariables = new Map([['server', 'value']]); + + expect(() => + BaseService.constructServiceURL(parameterizedUrl, defaultUrlVariables, providedUrlVariables) + ).toThrow( + /'server' is an invalid variable name\.\n\s*Valid variable names: \[domain,port,scheme\]\./ + ); + }); +});