diff --git a/src/v0/destinations/salesforce/utils.js b/src/v0/destinations/salesforce/utils.js index 24f3379eb9..2c2c7aa0cb 100644 --- a/src/v0/destinations/salesforce/utils.js +++ b/src/v0/destinations/salesforce/utils.js @@ -1,4 +1,9 @@ -const { RetryableError, ThrottledError, AbortedError } = require('@rudderstack/integrations-lib'); +const { + RetryableError, + ThrottledError, + AbortedError, + // isDefinedAndNotNull, +} = require('@rudderstack/integrations-lib'); const { handleHttpRequest } = require('../../../adapters/network'); const { getAuthErrCategoryFromStCode } = require('../../util'); const Cache = require('../../util/cache'); @@ -14,6 +19,55 @@ const { const ACCESS_TOKEN_CACHE = new Cache(ACCESS_TOKEN_CACHE_TTL); +const getErrorMessage = (response) => { + if (response && Array.isArray(response) && response[0]?.message?.length > 0) { + return response[0].message; + } + return JSON.stringify(response); +}; + +const handleAuthError = ( + errorCode, + authKey, + authorizationFlow, + sourceMessage, + destResponse, + status, +) => { + // eslint-disable-next-line sonarjs/no-small-switch + switch (errorCode) { + case 'INVALID_SESSION_ID': + if (authorizationFlow === OAUTH) { + throw new RetryableError( + `${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`, + 500, + destResponse, + getAuthErrCategoryFromStCode(status), + ); + } + ACCESS_TOKEN_CACHE.del(authKey); + throw new RetryableError( + `${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`, + 500, + destResponse, + ); + default: + throw new AbortedError( + `${DESTINATION} Request Failed: "${status}" due to "${getErrorMessage(destResponse.response)}", (Aborted) ${sourceMessage}`, + 400, + destResponse, + ); + } +}; + +const handleCommonAbortableError = (destResponse, sourceMessage, status) => { + throw new AbortedError( + `${DESTINATION} Request Failed: "${status}" due to "${getErrorMessage(destResponse.response)}", (Aborted) ${sourceMessage}`, + 400, + destResponse, + ); +}; + /** * ref: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/errorcodes.htm * handles Salesforce application level failures @@ -28,33 +82,20 @@ const salesforceResponseHandler = (destResponse, sourceMessage, authKey, authori const matchErrorCode = (errorCode) => response && Array.isArray(response) && response.some((resp) => resp?.errorCode === errorCode); - const getErrorMessage = () => { - if (response && Array.isArray(response) && response[0]?.message?.length > 0) { - return response[0].message; - } - return JSON.stringify(response); - }; - switch (status) { case 401: if (authKey && matchErrorCode('INVALID_SESSION_ID')) { - if (authorizationFlow === OAUTH) { - throw new RetryableError( - `${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`, - 500, - destResponse, - getAuthErrCategoryFromStCode(status), - ); - } - ACCESS_TOKEN_CACHE.del(authKey); - throw new RetryableError( - `${DESTINATION} Request Failed - due to "INVALID_SESSION_ID", (Retryable) ${sourceMessage}`, - 500, + handleAuthError( + 'INVALID_SESSION_ID', + authKey, + authorizationFlow, + sourceMessage, destResponse, + status, ); } + handleAuthError('DEFAULT', authKey, authorizationFlow, sourceMessage, destResponse, status); break; - case 403: if (matchErrorCode('REQUEST_LIMIT_EXCEEDED')) { throw new ThrottledError( @@ -76,12 +117,13 @@ const salesforceResponseHandler = (destResponse, sourceMessage, authKey, authori destResponse, ); } + handleCommonAbortableError(destResponse, sourceMessage, status); break; case 503: case 500: throw new RetryableError( - `${DESTINATION} Request Failed - due to "${getErrorMessage()}", (Retryable) ${sourceMessage}`, + `${DESTINATION} Request Failed - due to "${getErrorMessage(response)}", (Retryable) ${sourceMessage}`, 500, destResponse, ); @@ -89,7 +131,7 @@ const salesforceResponseHandler = (destResponse, sourceMessage, authKey, authori default: // Default case: aborting for all other error codes throw new AbortedError( - `${DESTINATION} Request Failed: "${status}" due to "${getErrorMessage()}", (Aborted) ${sourceMessage}`, + `${DESTINATION} Request Failed: "${status}" due to "${getErrorMessage(response)}", (Aborted) ${sourceMessage}`, 400, destResponse, ); diff --git a/test/integrations/destinations/salesforce/processor/data.ts b/test/integrations/destinations/salesforce/processor/data.ts index 7a44b6b8ed..7189e271eb 100644 --- a/test/integrations/destinations/salesforce/processor/data.ts +++ b/test/integrations/destinations/salesforce/processor/data.ts @@ -1476,10 +1476,10 @@ export const data = [ type: 'REST', method: 'POST', endpoint: - 'http://dummyurl.com/services/data/v50.0/sobjects/custom_object__c/a005g0000383kmUAAQ?_HttpMethod=PATCH', + 'https://ap15.salesforce.com/services/data/v50.0/sobjects/custom_object__c/a005g0000383kmUAAQ?_HttpMethod=PATCH', headers: { 'Content-Type': 'application/json', - Authorization: 'Bearer dummyAccessToken', + Authorization: 'Bearer dummy.access.token', }, params: {}, body: { diff --git a/test/integrations/destinations/salesforce/router/data.ts b/test/integrations/destinations/salesforce/router/data.ts index 9e26625188..7701ae6acf 100644 --- a/test/integrations/destinations/salesforce/router/data.ts +++ b/test/integrations/destinations/salesforce/router/data.ts @@ -630,7 +630,14 @@ export const data = [ type: 'identify', userId: '1e7673da-9473-49c6-97f7-da848ecafa76', }, - metadata: { jobId: 1, userId: 'u1' }, + metadata: { + jobId: 1, + userId: 'u1', + secret: { + access_token: 'dummy.access.token', + instance_url: 'https://ap15.salesforce.com', + }, + }, destination: { Config: { initialAccessToken: 'dummyInitialAccessToken', @@ -697,7 +704,15 @@ export const data = [ }, ], metadata: [ - { destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, jobId: 1, userId: 'u1' }, + { + destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, + jobId: 1, + userId: 'u1', + secret: { + access_token: 'dummy.access.token', + instance_url: 'https://ap15.salesforce.com', + }, + }, ], batched: false, statusCode: 200, @@ -787,7 +802,14 @@ export const data = [ type: 'identify', userId: '1e7673da-9473-49c6-97f7-da848ecafa76', }, - metadata: { jobId: 1, userId: 'u1' }, + metadata: { + jobId: 1, + userId: 'u1', + secret: { + access_token: 'dummy.access.token', + instance_url: 'https://ap15.salesforce.com', + }, + }, destination: { Config: { initialAccessToken: 'dummyInitialAccessToken', @@ -855,7 +877,15 @@ export const data = [ }, ], metadata: [ - { destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, jobId: 1, userId: 'u1' }, + { + destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, + jobId: 1, + userId: 'u1', + secret: { + access_token: 'dummy.access.token', + instance_url: 'https://ap15.salesforce.com', + }, + }, ], batched: false, statusCode: 200, @@ -945,7 +975,14 @@ export const data = [ type: 'identify', userId: '1e7673da-9473-49c6-97f7-da848ecafa76', }, - metadata: { jobId: 1, userId: 'u1' }, + metadata: { + jobId: 1, + userId: 'u1', + secret: { + access_token: 'dummy.access.token', + instance_url: 'https://ap15.salesforce.com', + }, + }, destination: { Config: { initialAccessToken: 'dummyInitialAccessToken', @@ -1013,7 +1050,15 @@ export const data = [ }, ], metadata: [ - { destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, jobId: 1, userId: 'u1' }, + { + destInfo: { authKey: '1WqFFH5esuVPnUgHkvEoYxDcX3y' }, + jobId: 1, + userId: 'u1', + secret: { + access_token: 'dummy.access.token', + instance_url: 'https://ap15.salesforce.com', + }, + }, ], batched: false, statusCode: 200,