Skip to content

Commit

Permalink
feat: move hubspot to transformer proxy to enable partial batch handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsSudip committed Apr 24, 2024
1 parent bac3cc5 commit 722f3d1
Show file tree
Hide file tree
Showing 5 changed files with 767 additions and 0 deletions.
101 changes: 101 additions & 0 deletions src/v1/destinations/hs/networkHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/* eslint-disable no-param-reassign */
/* eslint-disable no-restricted-syntax */
const { removeUndefinedAndNullValues } = require('@rudderstack/integrations-lib');
const { TransformerProxyError } = require('../../../v0/util/errorTypes');
const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network');
const { isHttpStatusSuccess, getAuthErrCategoryFromStCode } = require('../../../v0/util/index');

const {
processAxiosResponse,
getDynamicErrorType,
} = require('../../../adapters/utils/networkUtils');
const tags = require('../../../v0/util/tags');

const populateErrorMessage = (response) => {
const errorResponse = {
message: response?.message || null,
category: response?.category || null,
correlationId: response?.correlationId || null,
};
removeUndefinedAndNullValues(errorResponse);
if (Object.keys(errorResponse).length === 0) {
return 'unknown error format';

Check warning on line 22 in src/v1/destinations/hs/networkHandler.js

View check run for this annotation

Codecov / codecov/patch

src/v1/destinations/hs/networkHandler.js#L22

Added line #L22 was not covered by tests
}
return JSON.stringify(errorResponse);
};

const responseHandler = (responseParams) => {
const { destinationResponse, rudderJobMetadata } = responseParams;
const message = `[HUBSPOT Response V1 Handler] - Request Processed Successfully`;
const responseWithIndividualEvents = [];
const { response, status } = destinationResponse;

if (isHttpStatusSuccess(status)) {
// populate different response for each event
const results = response?.results;
if (Array.isArray(results)) {
for (const [idx] of results.entries()) {
const proxyOutputObj = {
statusCode: 200,
metadata: rudderJobMetadata[idx],
error: 'success',
};
responseWithIndividualEvents.push(proxyOutputObj);
}
}

return {
status,
message,
destinationResponse,
response: responseWithIndividualEvents,
};
}

// in case of failure status, populate response to maintain len(metadata)=len(response)
const errorMessage = populateErrorMessage(response);

// At least one event in the batch is invalid.
if (status === 400 && rudderJobMetadata.length > 1) {
if (rudderJobMetadata.length > 1) {
for (const metadata of rudderJobMetadata) {
metadata.dontBatch = true;
responseWithIndividualEvents.push({
statusCode: status,
metadata,
error: errorMessage,
});
}
}
// sending back 500 for retry only when events came in a batch
throw new TransformerProxyError(
`HUBSPOT: Error transformer proxy v1 during HUBSPOT response transformation`,
500,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(500),
},
destinationResponse,
'',
responseWithIndividualEvents,
);
}
throw new TransformerProxyError(
`HUBSPOT: Error transformer proxy v1 during HUBSPOT response transformation`,
status,
{
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
destinationResponse,
getAuthErrCategoryFromStCode(status),
responseWithIndividualEvents,
);
};

function networkHandler() {
this.prepareProxy = prepareProxyRequest;
this.proxy = proxyRequest;
this.processAxiosResponse = processAxiosResponse;
this.responseHandler = responseHandler;
}

module.exports = { networkHandler };
261 changes: 261 additions & 0 deletions test/integrations/destinations/hs/dataDelivery/business.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
import { generateMetadata, generateProxyV1Payload } from '../../../testUtils';

const commonStatTags = {
destType: 'HS',
destinationId: 'default-destinationId',
errorCategory: 'network',
errorType: 'retryable',
feature: 'dataDelivery',
implementation: 'native',
module: 'destination',
workspaceId: 'default-workspaceId',
};
export const businessData = [
{
name: 'hs',
description: 'successfully creating users from a batch',
feature: 'dataDelivery',
module: 'destination',
version: 'v1',
input: {
request: {
body: generateProxyV1Payload(
{
endpoint: 'https://api.hubapi.com/crm/v3/objects/contacts/batch/update',
JSON: {
inputs: [
{
properties: {
firstname: 'testmail1217',
},
id: '12877907024',
},
{
properties: {
firstname: 'test1',
email: '[email protected]',
},
id: '12877907025',
},
],
},
},
[generateMetadata(1), generateMetadata(2)],
),
},
},
output: {
response: {
status: 200,
body: {
output: {
status: 200,
message: '[HUBSPOT Response V1 Handler] - Request Processed Successfully',
response: [
{
error: 'success',
metadata: generateMetadata(1),
statusCode: 200,
},
{
error: 'success',
metadata: generateMetadata(2),
statusCode: 200,
},
],
destinationResponse: {
response: {
status: 'COMPLETE',
results: [
{
id: '12877907025',
properties: {
createdate: '2024-04-16T09:50:16.034Z',
email: '[email protected]',
firstname: 'test1',
hs_is_unworked: 'true',
hs_object_id: '12877907025',
hs_pipeline: 'contacts-lifecycle-pipeline',
lastmodifieddate: '2024-04-23T11:52:03.723Z',
lifecyclestage: 'lead',
},
createdAt: '2024-04-16T09:50:16.034Z',
updatedAt: '2024-04-23T11:52:03.723Z',
archived: false,
},
{
id: '12877907024',
properties: {
createdate: '2024-04-16T09:50:16.034Z',
firstname: 'testmail1217',
hs_is_unworked: 'true',
hs_object_id: '12877907024',
hs_pipeline: 'contacts-lifecycle-pipeline',
lastmodifieddate: '2024-04-23T11:52:03.723Z',
lifecyclestage: 'lead',
},
createdAt: '2024-04-16T09:50:16.034Z',
updatedAt: '2024-04-23T11:52:03.723Z',
archived: false,
},
],
startedAt: '2024-04-24T05:11:51.090Z',
completedAt: '2024-04-24T05:11:51.190Z',
},
status: 200,
},
},
},
},
},
},
{
name: 'hs',
description: 'failed due to duplicate object in a batch',
feature: 'dataDelivery',
module: 'destination',
version: 'v1',
input: {
request: {
body: generateProxyV1Payload(
{
endpoint: 'https://api.hubapi.com/crm/v3/objects/contacts/batch/update',
JSON: {
inputs: [
{
properties: {
firstname: 'test5',
email: '[email protected]',
},
id: '12877907025',
},
{
properties: {
firstname: 'testmail1217',
email: '[email protected]',
},
id: '12877907025',
},
],
},
},
[generateMetadata(1), generateMetadata(2)],
),
},
},
output: {
response: {
status: 200,
body: {
output: {
message: 'HUBSPOT: Error transformer proxy v1 during HUBSPOT response transformation',
response: [
{
error:
'{"status":"error","message":"Duplicate IDs found in batch input: [12877907025]. IDs must be unique","correlationId":"d24ec5cd-8998-4674-a928-59603ae6b0eb","context":{"ids":["12877907025"]},"category":"VALIDATION_ERROR"}',
metadata: {
...generateMetadata(1),
dontBatch: true,
},
statusCode: 500,
},
{
error:
'{"status":"error","message":"Duplicate IDs found in batch input: [12877907025]. IDs must be unique","correlationId":"d24ec5cd-8998-4674-a928-59603ae6b0eb","context":{"ids":["12877907025"]},"category":"VALIDATION_ERROR"}',
metadata: {
...generateMetadata(2),
dontBatch: true,
},
statusCode: 500,
},
],
statTags: commonStatTags,
status: 500,
},
},
},
},
},
{
name: 'hs',
description: 'failed due to wrong email format in a batch',
feature: 'dataDelivery',
module: 'destination',
version: 'v1',
input: {
request: {
body: generateProxyV1Payload(
{
endpoint: 'https://api.hubapi.com/crm/v3/objects/contacts/batch/update',
JSON: {
inputs: [
[
{
properties: {
firstname: 'test1',
email: '[email protected]',
},
},
{
properties: {
firstname: 'testmail1217',
email: '[email protected]',
},
},
{
properties: {
firstname: 'test5',
email: '[email protected]',
},
},
],
],
},
},
[generateMetadata(1), generateMetadata(2), generateMetadata(3)],
),
},
},
output: {
response: {
status: 200,
body: {
output: {
message: 'HUBSPOT: Error transformer proxy v1 during HUBSPOT response transformation',
response: [
{
error:
'{"status":"error","message":"Invalid input JSON on line 3, column 9: Cannot deserialize value of type `com.hubspot.inbounddb.publicobject.core.v2.SimplePublicObjectBatchInput$Json` from Array value (token `JsonToken.START_ARRAY`)","correlationId":"99df04b9-da11-4504-bd97-2c15f58d0943"}',
metadata: {
...generateMetadata(1),
dontBatch: true,
},
statusCode: 500,
},
{
error:
'{"status":"error","message":"Invalid input JSON on line 3, column 9: Cannot deserialize value of type `com.hubspot.inbounddb.publicobject.core.v2.SimplePublicObjectBatchInput$Json` from Array value (token `JsonToken.START_ARRAY`)","correlationId":"99df04b9-da11-4504-bd97-2c15f58d0943"}',
metadata: {
...generateMetadata(2),
dontBatch: true,
},
statusCode: 500,
},
{
error:
'{"status":"error","message":"Invalid input JSON on line 3, column 9: Cannot deserialize value of type `com.hubspot.inbounddb.publicobject.core.v2.SimplePublicObjectBatchInput$Json` from Array value (token `JsonToken.START_ARRAY`)","correlationId":"99df04b9-da11-4504-bd97-2c15f58d0943"}',
metadata: {
...generateMetadata(3),
dontBatch: true,
},
statusCode: 500,
},
],
statTags: commonStatTags,
status: 500,
},
},
},
},
},
];
4 changes: 4 additions & 0 deletions test/integrations/destinations/hs/dataDelivery/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { businessData } from './business';
import { otherData } from './other';

export const data = [...businessData, ...otherData];
Loading

0 comments on commit 722f3d1

Please sign in to comment.