diff --git a/README.md b/README.md index eb2235c..4d144c9 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ and max number of retries

EventsCoreAPIOptions : object
+
ProviderFilterOptions : object
+
+
ProviderOptions : object
+
ProviderInputModel : object
EventMetadataInputModel : object
@@ -145,11 +149,12 @@ and max number of retries * [.apiKey](#EventsCoreAPI+apiKey) * [.accessToken](#EventsCoreAPI+accessToken) * [.init(organizationId, apiKey, accessToken, [httpOptions])](#EventsCoreAPI+init) ⇒ [Promise.<EventsCoreAPI>](#EventsCoreAPI) - * [.getAllProviders(consumerOrgId)](#EventsCoreAPI+getAllProviders) ⇒ Promise.<object> + * [.getAllProviders(consumerOrgId, providerOptions)](#EventsCoreAPI+getAllProviders) ⇒ Promise.<object> * [.getProvider(providerId, [fetchEventMetadata])](#EventsCoreAPI+getProvider) ⇒ Promise.<object> * [.createProvider(consumerOrgId, projectId, workspaceId, body)](#EventsCoreAPI+createProvider) ⇒ Promise.<object> * [.updateProvider(consumerOrgId, projectId, workspaceId, providerId, body)](#EventsCoreAPI+updateProvider) ⇒ Promise.<object> * [.deleteProvider(consumerOrgId, projectId, workspaceId, providerId)](#EventsCoreAPI+deleteProvider) ⇒ Promise.<object> + * [.getProviderMetadata()](#EventsCoreAPI+getProviderMetadata) ⇒ Promise.<object> * [.getAllEventMetadataForProvider(providerId)](#EventsCoreAPI+getAllEventMetadataForProvider) ⇒ Promise.<object> * [.getEventMetadataForProvider(providerId, eventCode)](#EventsCoreAPI+getEventMetadataForProvider) ⇒ Promise.<object> * [.createEventMetadataForProvider(consumerOrgId, projectId, workspaceId, providerId, body)](#EventsCoreAPI+createEventMetadataForProvider) ⇒ Promise.<object> @@ -208,7 +213,7 @@ Initialize SDK. -### eventsCoreAPI.getAllProviders(consumerOrgId) ⇒ Promise.<object> +### eventsCoreAPI.getAllProviders(consumerOrgId, providerOptions) ⇒ Promise.<object> Fetch all the providers **Kind**: instance method of [EventsCoreAPI](#EventsCoreAPI) @@ -217,6 +222,7 @@ Fetch all the providers | Param | Type | Description | | --- | --- | --- | | consumerOrgId | string | Consumer Org Id from the console | +| providerOptions | [ProviderOptions](#ProviderOptions) | Provider options | @@ -277,6 +283,11 @@ Delete a provider given the id | workspaceId | string | Workspace Id from the console | | providerId | string | The id that uniquely identifies the provider to be deleted | + + +### eventsCoreAPI.getProviderMetadata() ⇒ Promise.<object> +**Kind**: instance method of [EventsCoreAPI](#EventsCoreAPI) +**Returns**: Promise.<object> - Returns the list of all entitled provider metadata for the org ### eventsCoreAPI.getAllEventMetadataForProvider(providerId) ⇒ Promise.<object> @@ -544,6 +555,29 @@ Returns a Promise that resolves with a new EventsCoreAPI object. | [eventsBaseURL] | string | Base URL for Events Default https://api.adobe.io (optional) | | [eventsIngressURL] | string | Ingress URL for Events. Default https://eventsingress.adobe.io (optional) | + + +## ProviderFilterOptions : object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| [providerMetadataId] | string | Fetch by providerMetadataId for the consumer org | +| [instanceId] | string | For Self registered providers, instanceId is a must while fetching by providerMetadataId | +| [providerMetadataIds] | Array.<string> | Fetch all providers ( and all instances ) for the list of provider metadata ids | + + + +## ProviderOptions : object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| fetchEventMetadata | boolean | Option to fetch event metadata for each of the the providers in the list | +| filterBy | [ProviderFilterOptions](#ProviderFilterOptions) | Provider filtering options based on either (providerMetadataId and instanceId) or list of providerMetadataIds | + ## ProviderInputModel : object diff --git a/src/SDKErrors.js b/src/SDKErrors.js index 02f353b..9d01aa3 100644 --- a/src/SDKErrors.js +++ b/src/SDKErrors.js @@ -50,6 +50,7 @@ E('ERROR_GET_PROVIDER', '%s') E('ERROR_CREATE_PROVIDER', '%s') E('ERROR_UPDATE_PROVIDER', '%s') E('ERROR_DELETE_PROVIDER', '%s') +E('ERROR_GET_ALL_PROVIDER_METADATA', '%s') E('ERROR_GET_ALL_EVENTMETADATA', '%s') E('ERROR_GET_EVENTMETADATA', '%s') E('ERROR_CREATE_EVENTMETADATA', '%s') diff --git a/src/helpers.js b/src/helpers.js index e017a49..44046b0 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -30,21 +30,19 @@ function reduceError (error = {}) { * Appends querystring key/value pairs to a url * * @param {string} url URL - * @param {object} qs Object/map with all the query paratemers as key value pairs + * @param {object} qs Object/map with all the query parameters as key value pairs * @returns {string} URL with appended querystring key/value pairs */ function appendQueryParams (url, qs) { let result = url - if (qs) { - let separator = (url.indexOf('?') >= 0) ? '&' : '?' - for (const key of Object.getOwnPropertyNames(qs)) { - if (qs[key]) { - const escKey = querystring.escape(key) - const escValue = querystring.escape(qs[key]) - result += `${separator}${escKey}=${escValue}` - separator = '&' - } + if (qs && !(Object.keys(qs).length === 0)) { + const filteredQs = Object.entries(qs).filter(([k, v]) => !(v === null || v === undefined)) + if (Object.keys(filteredQs).length === 0) { + return result } + const separator = (url.indexOf('?') >= 0) ? '&' : '?' + const queryParams = querystring.stringify(Object.fromEntries(filteredQs)) + result += `${separator}${queryParams}` } return result } diff --git a/src/index.js b/src/index.js index 4a26b51..25200a6 100644 --- a/src/index.js +++ b/src/index.js @@ -111,17 +111,35 @@ class EventsCoreAPI { * ========================================================================= */ + /** + * @typedef {object} ProviderFilterOptions + * @property {string} [providerMetadataId] Fetch by providerMetadataId for the consumer org + * @property {string} [instanceId] For Self registered providers, instanceId is a must while fetching by providerMetadataId + * @property {Array.} [providerMetadataIds] Fetch all providers ( and all instances ) for the list of provider metadata ids + */ + /** + * @typedef {object} ProviderOptions + * @property {boolean} fetchEventMetadata Option to fetch event metadata for each of the the providers in the list + * @property {ProviderFilterOptions} filterBy Provider filtering options based on either (providerMetadataId and instanceId) or list of providerMetadataIds + */ /** * Fetch all the providers * * @param {string} consumerOrgId Consumer Org Id from the console + * @param {ProviderOptions} providerOptions Provider options * @returns {Promise} Returns list of providers for the org */ - getAllProviders (consumerOrgId) { + getAllProviders (consumerOrgId, providerOptions = {}) { const headers = {} + const filterOptions = providerOptions.filterBy + if (filterOptions && filterOptions.providerMetadataIds && filterOptions.providerMetadataId) { + return Promise.reject(new codes.ERROR_GET_ALL_PROVIDERS({ messageValues: 'Only one of providerMetadataIds or providerMetadataId can be set' })) + } const requestOptions = this.__createRequest('GET', headers) const url = this.__getUrl(`/events/${consumerOrgId}/providers`) - const sdkDetails = { requestOptions: requestOptions, url: url } + let urlWithQueryParams = helpers.appendQueryParams(url, filterOptions) + urlWithQueryParams = helpers.appendQueryParams(urlWithQueryParams, { eventmetadata: providerOptions.fetchEventMetadata }) + const sdkDetails = { requestOptions: requestOptions, url: urlWithQueryParams } return this.__handleRequest(sdkDetails, codes.ERROR_GET_ALL_PROVIDERS) } @@ -135,8 +153,9 @@ class EventsCoreAPI { getProvider (providerId, fetchEventMetadata = false) { const headers = {} const requestOptions = this.__createRequest('GET', headers) - const url = this.__getUrl(`/events/providers/${providerId}?eventmetadata=${fetchEventMetadata}`) - const sdkDetails = { requestOptions: requestOptions, url: url } + const url = this.__getUrl(`/events/providers/${providerId}`) + const urlWithQueryParams = helpers.appendQueryParams(url, { eventmetadata: fetchEventMetadata }) + const sdkDetails = { requestOptions: requestOptions, url: urlWithQueryParams } return this.__handleRequest(sdkDetails, codes.ERROR_GET_PROVIDER) } @@ -200,6 +219,23 @@ class EventsCoreAPI { return this.__handleRequest(sdkDetails, codes.ERROR_DELETE_PROVIDER) } + /** + * ========================================================================= + * GET Entitled Provider Metadata + * ========================================================================= + */ + + /** + * @returns {Promise} Returns the list of all entitled provider metadata for the org + */ + getProviderMetadata () { + const headers = {} + const requestOptions = this.__createRequest('GET', headers) + const url = this.__getUrl('/events/providermetadata') + const sdkDetails = { requestOptions: requestOptions, url: url } + return this.__handleRequest(sdkDetails, codes.ERROR_GET_ALL_PROVIDER_METADATA) + } + /** * ========================================================================= * GET/POST/PUT/DELETE Event Metadata @@ -424,7 +460,7 @@ class EventsCoreAPI { * @param {Page} [page] page size and page number * @returns {Promise} Paginated response of all webhook/journal registrations for an org */ - getAllRegistrationsForOrg (consumerOrgId, page) { + getAllRegistrationsForOrg (consumerOrgId, page = {}) { const headers = {} const requestOptions = this.__createRequest('GET', headers) const url = this.__getUrl(`/events/${consumerOrgId}/registrations`) @@ -633,6 +669,9 @@ class EventsCoreAPI { .then((response) => { if (!response.ok) { sdkDetails.requestId = response.headers.get('x-request-id') + if (response.status === 409) { + sdkDetails.conflictingId = response.headers.get('x-conflicting-id') + } throw Error(helpers.reduceError(response)) } if (response.status === 204) { resolve() } else { resolve(response.json()) } diff --git a/test/helpers.test.js b/test/helpers.test.js index f0721a9..4f60270 100644 --- a/test/helpers.test.js +++ b/test/helpers.test.js @@ -54,6 +54,31 @@ describe('Append query params test', () => { const url = helpers.appendQueryParams('https://base-url.adobe.io?limit=2&latest=true', queryParams3) expect(url).toBe('https://base-url.adobe.io?limit=2&latest=true&interval=10') }) + it('Append query params to url with array query params', () => { + const queryParams3 = { values: ['value1', 'value 2', 'value3'] } + const url = helpers.appendQueryParams('https://base-url.adobe.io', queryParams3) + expect(url).toBe('https://base-url.adobe.io?values=value1&values=value%202&values=value3') + }) + it('Do not append undefined query params to url with query params', () => { + const queryParams3 = { values: undefined, interval: 10 } + const url = helpers.appendQueryParams('https://base-url.adobe.io', queryParams3) + expect(url).toBe('https://base-url.adobe.io?interval=10') + }) + it('Append false value query params to url with query params', () => { + const queryParams3 = { value1: false, value2: false, value3: null, interval: 10 } + const url = helpers.appendQueryParams('https://base-url.adobe.io', queryParams3) + expect(url).toBe('https://base-url.adobe.io?value1=false&value2=false&interval=10') + }) + it('Do not append undefined query params to url with array query params', () => { + const queryParams3 = { values: undefined, interval: [10, 20, 30] } + const url = helpers.appendQueryParams('https://base-url.adobe.io', queryParams3) + expect(url).toBe('https://base-url.adobe.io?interval=10&interval=20&interval=30') + }) + it('Do not append undefined query params to url ', () => { + const queryParams3 = { values: undefined } + const url = helpers.appendQueryParams('https://base-url.adobe.io', queryParams3) + expect(url).toBe('https://base-url.adobe.io') + }) }) describe('Proper Payload Test', () => { diff --git a/test/index.test.js b/test/index.test.js index 4917a07..aa6915e 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -46,6 +46,7 @@ const gAccessToken = 'test-token' const journalUrl = 'http://journal-url/events/organizations/orgId/integrations/integId/regId' const EVENTS_BASE_URL = 'https://api.adobe.io/events' const EVENTS_INGRESS_URL = 'https://eventsingress.adobe.io' +const CONFLICTING_ID = 'conflictingId' // ///////////////////////////////////////////// @@ -128,6 +129,53 @@ describe('test get all providers', () => { expect(res._embedded.providers[0].id).toBe('test-id-1') expect(res._embedded.providers[1].id).toBe('test-id-2') }) + it('Success on get all providers for provider metadata ids list', async () => { + const sdkClient = await createSdkClient() + exponentialBackoffMockReturnValue(mock.data.getAllProvidersResponse, { status: 200, statusText: 'OK' }) + const res = await sdkClient.getAllProviders('consumerId', + { + fetchEventMetadata: false, + filterBy: { providerMetadataIds: ['pm-1', 'pm-2'] } + }) + expect(res._embedded.providers.length).toBe(2) + expect(res._embedded.providers[0].provider_metadata).toBe('pm-1') + expect(res._embedded.providers[1].provider_metadata).toBe('pm-2') + }) + it('Success on get all providers for a provider metadata id and instance id', async () => { + const sdkClient = await createSdkClient() + const returnedValue = mock.data.getAllProvidersResponse + returnedValue._embedded.providers.pop() + exponentialBackoffMockReturnValue(returnedValue, { status: 200, statusText: 'OK' }) + const res = await sdkClient.getAllProviders('consumerId', + { + fetchEventMetadata: false, + filterBy: { providerMetadataId: 'pm-1', instanceId: 'instance-1' } + }) + expect(res._embedded.providers.length).toBe(1) + expect(res._embedded.providers[0].id).toBe('test-id-1') + expect(res._embedded.providers[0].provider_metadata).toBe('pm-1') + expect(res._embedded.providers[0].instance_id).toBe('instance-1') + }) + it('Success on get all providers with eventmetadata', async () => { + const sdkClient = await createSdkClient() + exponentialBackoffMockReturnValue(mock.data.getAllProvidersWithEventMetadataResponse, { status: 200, statusText: 'OK' }) + const res = await sdkClient.getAllProviders('consumerId', { fetchEventMetadata: true }) + expect(res._embedded.providers.length).toBe(1) + expect(res._embedded.providers[0].id).toBe('test-id-1') + expect(res._embedded.providers[0]._embedded.eventmetadata[0].event_code).toBe('com.adobe.events.sdk.event.test') + }) + it('Error on get all providers with providerMetadataIds list and providerMetadatataId query params', async () => { + const api = 'getAllProviders' + await checkErrorResponse(api, new errorSDK.codes.ERROR_GET_ALL_PROVIDERS(), ['consumerId', + { + fetchEventMetadata: false, + filterBy: { + providerMetadataIds: ['pm1', 'pm2'], + providerMetadataId: 'pm1' + } + } + ]) + }) it('Not found error on get all providers ', async () => { const api = 'getAllProviders' exponentialBackoffMockReturnValue({}, { status: 404, statusText: 'Not Found' }) @@ -218,6 +266,22 @@ describe('test delete provider', () => { }) }) +// //////////////////////////////////////////// + +describe('test get provider metadata', () => { + it('Success on get provider metadata for org', async () => { + const sdkClient = await createSdkClient() + exponentialBackoffMockReturnValue(mock.data.getProviderMetadataForOrg, { status: 200, statusText: 'OK' }) + const res = await sdkClient.getProviderMetadata() + expect(res._embedded.providermetadata.length).toBe(2) + }) + it('Not found error on get provider metadata', async () => { + const api = 'getProviderMetadata' + exponentialBackoffMockReturnValue({}, { status: 400, statusText: 'Bad Request' }) + await checkErrorResponse(api, new errorSDK.codes.ERROR_GET_ALL_PROVIDER_METADATA()) + }) +}) + // ///////////////////////////////////////////// describe('Get all event metadata for provider', () => { @@ -348,6 +412,13 @@ describe('Create registration', () => { exponentialBackoffMockReturnValue({}, { status: 400, statusText: 'Bad Request' }) await checkErrorResponse(api, new errorSDK.codes.ERROR_CREATE_REGISTRATION(), ['consumerId', 'projectId', 'workspaceId', mock.data.createRegistrationBadRequest]) }) + it('Conflcit in name on create registration', async () => { + const api = 'createRegistration' + const mockHeaders = {} + mockHeaders['x-conflicting-id'] = CONFLICTING_ID + exponentialBackoffMockReturnValue({}, { status: 409, statusText: 'Conflict', headers: mockHeaders }) + await checkErrorResponse(api, new errorSDK.codes.ERROR_CREATE_REGISTRATION(), ['consumerId', 'projectId', 'workspaceId', mock.data.createRegistrationBadRequest]) + }) }) describe('Update registration', () => { @@ -689,6 +760,9 @@ async function checkErrorResponse (fn, error, args = []) { .catch(e => { expect(e.name).toEqual(error.name) expect(e.code).toEqual(error.code) + if (e.code === 409) { + expect(e.conflictingId).toEqual(CONFLICTING_ID) + } resolve() }) }) diff --git a/test/mock.js b/test/mock.js index a875dcd..3b61013 100644 --- a/test/mock.js +++ b/test/mock.js @@ -90,7 +90,9 @@ const getAllProvidersResponse = { id: 'test-id-1', label: 'label 1', source: 'urn:uuid:source1', - publisher: 'Adobe' + publisher: 'Adobe', + provider_metadata: 'pm-1', + instance_id: 'instance-1' }, { _links: { @@ -107,7 +109,59 @@ const getAllProvidersResponse = { id: 'test-id-2', label: 'label 2', source: 'urn:uuid:source2', - publisher: 'adobeOrg2@AdobeOrg' + publisher: 'adobeOrg2@AdobeOrg', + provider_metadata: 'pm-2' + } + ] + } +} + +const getAllProvidersWithEventMetadataResponse = { + _links: { + self: { + href: 'https://api.adobe.io/events/consumerOrgId/providers' + } + }, + _embedded: { + providers: [ + { + _links: { + 'rel:eventmetadata': { + href: 'https://api.adobe.io/events/providers/test-id-1/eventmetadata' + }, + 'rel:update': { + href: 'https://api.adobe.io/events/consumerId/projectId/workspaceId/providers/test-id-1' + }, + self: { + href: 'https://api.adobe.io/events/providers/test-id-1' + } + }, + id: 'test-id-1', + label: 'label 1', + source: 'urn:uuid:source1', + publisher: 'Adobe', + provider_metadata: 'pm-1', + instance_id: 'instance-1', + _embedded: { + eventmetadata: [ + { + _links: { + 'rel:sample_event': { + href: 'https://api.adobe.io/events/providers/test-id/eventmetadata/com.adobe.events.sdk.event.test/sample_event' + }, + 'rel:update': { + href: 'https://api.adobe.io/events/consumerId/projectId/workspaceId/providers/test-id/eventmetadata/com.adobe.events.sdk.event.test' + }, + self: { + href: 'https://api.adobe.io/events/providers/test-id/eventmetadata/com.adobe.events.sdk.event.test' + } + }, + description: 'Test for Events SDK', + label: 'EventsSDK test', + event_code: 'com.adobe.events.sdk.event.test' + } + ] + } } ] } @@ -178,6 +232,32 @@ const createEventMetadataForProviderResponse = { event_code: 'com.adobe.event_code_1' } +const getProviderMetadataForOrg = { + _links: { + self: { + href: 'https://api.adobe.io/events/providermetadata' + } + }, + _embedded: { + providermetadata: [ + { + id: 'id-1', + group: 'Experience Platform', + label: 'Id 1', + description: 'A Id 1 provider, registered by your organization.', + has_multiple_providers: true + }, + { + id: 'id-2', + group: 'Experience Cloud', + label: 'Id 2', + description: 'An Id 2 instance registered as an Adobe I/O events provider', + has_multiple_providers: false + } + ] + } +} + const getAllEventMetadataResponse = { _links: { self: { @@ -797,11 +877,13 @@ const data = { providerResponse: providerResponse, providerWithEventMetadataResponse: providerWithEventMetadataResponse, getAllProvidersResponse: getAllProvidersResponse, + getAllProvidersWithEventMetadataResponse: getAllProvidersWithEventMetadataResponse, createProvider: createProvider, createProviderBadRequest: createProviderBadRequest, updateProvider: updateProvider, updateProviderBadRequest: updateProviderBadRequest, updateProviderResponse: updateProviderResponse, + getProviderMetadataForOrg: getProviderMetadataForOrg, getAllEventMetadataResponse: getAllEventMetadataResponse, getEventMetadataResponse: getEventMetadataResponse, createEventMetadataForProvider: createEventMetadataForProvider, diff --git a/types.d.ts b/types.d.ts index 3660983..168ac46 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,13 +1,16 @@ import {Observable} from "rxjs"; /** - * @typedef {object} EventsCoreAPIOptions - * @property {number} [timeout] Http request timeout in ms (optional) - * @property {number} [retries] Number of retries in case of 5xx errors. Default 0 (optional) + * @property [timeout] - Http request timeout in ms (optional) + * @property [retries] - Number of retries in case of 5xx errors. Default 0 (optional) + * @property [eventsBaseURL] - Base URL for Events Default https://api.adobe.io (optional) + * @property [eventsIngressURL] - Ingress URL for Events. Default https://eventsingress.adobe.io (optional) */ declare type EventsCoreAPIOptions = { timeout?: number; retries?: number; + eventsBaseURL?: string; + eventsIngressURL?: string; }; /** @@ -55,9 +58,10 @@ declare class EventsCoreAPI { /** * Fetch all the providers * @param consumerOrgId - Consumer Org Id from the console + * @param providerOptions - Provider options * @returns Returns list of providers for the org */ - getAllProviders(consumerOrgId: string): Promise; + getAllProviders(consumerOrgId: string, providerOptions: ProviderOptions): Promise; /** * Fetch a provider * @param providerId - The id that uniquely identifies the provider to be fetched @@ -93,6 +97,10 @@ declare class EventsCoreAPI { * @returns Returns an empty object if the deletion was successful */ deleteProvider(consumerOrgId: string, projectId: string, workspaceId: string, providerId: string): Promise; + /** + * @returns Returns the list of all entitled provider metadata for the org + */ + getProviderMetadata(): Promise; /** * Get all event metadata for a provider * @param providerId - The id that uniquely identifies the provider whose event metadata is to be fetched @@ -241,6 +249,26 @@ declare class EventsCoreAPI { verifyDigitalSignatureForEvent(event: any, recipientClientId: string, signatureOptions?: SignatureOptions): boolean; } +/** + * @property [providerMetadataId] - Fetch by providerMetadataId for the consumer org + * @property [instanceId] - For Self registered providers, instanceId is a must while fetching by providerMetadataId + * @property [providerMetadataIds] - Fetch all providers ( and all instances ) for the list of provider metadata ids + */ +declare type ProviderFilterOptions = { + providerMetadataId?: string; + instanceId?: string; + providerMetadataIds?: string[]; +}; + +/** + * @property fetchEventMetadata - Option to fetch event metadata for each of the the providers in the list + * @property filterBy - Provider filtering options based on either (providerMetadataId and instanceId) or list of providerMetadataIds + */ +declare type ProviderOptions = { + fetchEventMetadata: boolean; + filterBy: ProviderFilterOptions; +}; + /** * @property label - The label of this Events Provider * @property [description] - The description of this Events Provider