Skip to content

Commit

Permalink
chore: onboard rakuten proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
anantjain45823 committed Feb 1, 2024
1 parent e243682 commit f5dd832
Show file tree
Hide file tree
Showing 6 changed files with 458 additions and 3 deletions.
5 changes: 4 additions & 1 deletion src/cdk/v2/destinations/rakuten/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { InstrumentationError } = require('@rudderstack/integrations-lib');
const { isDefinedAndNotNull } = require('rudder-transformer-cdk/build/utils');
const { mappingConfig, ConfigCategories, productProperties } = require('./config');
const { constructPayload } = require('../../../../v0/util');

Expand All @@ -25,7 +26,9 @@ const constructLineItems = (properties) => {
// mapping all the properties leaving amount as for amount we need to do some calculations
Object.keys(productProperties).forEach((property) => {
const propertyKey = productProperties[property];
const values = properties.products.map((product) => product?.[propertyKey] || '');
const values = properties.products.map((product) =>
isDefinedAndNotNull(product?.[propertyKey]) ? product[propertyKey] : '',
);
if (values.some((element) => element !== '')) {
productList[property] = values.join('|');
}
Expand Down
108 changes: 108 additions & 0 deletions src/v0/destinations/rakuten/networkHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
const {
NetworkError,
InstrumentationError,
ConfigurationError,
} = require('@rudderstack/integrations-lib');
const { httpSend } = require('../../../adapters/network');
const {
processAxiosResponse,
getDynamicErrorType,
} = require('../../../adapters/utils/networkUtils');

const DESTINATION = 'RAKUTEN';
const { TAG_NAMES } = require('../../util/tags');
const { HTTP_STATUS_CODES } = require('../../util/constant');

const prepareProxyRequest = (request) => request;
const proxyRequest = async (request, destType) => {
const { endpoint, data, method, params, headers } = prepareProxyRequest(request);
const requestOptions = {
url: endpoint,
data,
params,
headers,
method,
};
const response = await httpSend(requestOptions, { feature: 'proxy', destType });
return response;
};
const extractContent = (xmlPayload, tagName) => {
const pattern = new RegExp(`<${tagName}>(.*?)</${tagName}>`);
const match = xmlPayload.match(pattern);
return match ? match[1] : null;
};

const responseHandler = (destinationResponse) => {
const msg = `[${DESTINATION} Response Handler] - Request Processed Successfully`;
const { response, status } = destinationResponse;
if (status === 400) {
throw new ConfigurationError(
`Request failed with status: ${status} due to invalid Marketing Id`,
status,
{
[TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
destinationResponse,
);
}
// Extract errors, good and bad between different tags
const badRecords = extractContent(response, 'bad');
const errors = extractContent(response, 'error');

// For access denied for a mid rakuten sends status code 200 with response as <response> <error> Access denied </error> </response>
if (errors) {
throw new ConfigurationError(
`Request failed with status: ${status} due to ${errors}. Can you try to enable pixel tracking for this mid.`,
status,
{
// status would be 200 but since no error type for this status code hence it will take it as aborted
[TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
destinationResponse,
);
}
if (parseInt(badRecords, 10)) {
throw new InstrumentationError(
`Request failed with status: ${status} with number of bad records ${badRecords}`,
status,
{
// status would be 200 but since no error type for this status code hence it will take it as aborted
[TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
destinationResponse,
);
}
/* just puttting it here for 429 and 500's we dont have documentation for these two
neither we have any sample response but just in case if we recoeve non 2xx status
*/
if (status !== 200) {
throw new NetworkError(

Check warning on line 79 in src/v0/destinations/rakuten/networkHandler.js

View check run for this annotation

Codecov / codecov/patch

src/v0/destinations/rakuten/networkHandler.js#L79

Added line #L79 was not covered by tests
`Request failed with status: ${status}`,
status,
{
[TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
destinationResponse,
);
}
// if no error or bad record is found and status is 200 the request is successfull
return {
status: HTTP_STATUS_CODES.OK,
message: msg,
destinationResponse,
};
};

// eslint-disable-next-line @typescript-eslint/naming-convention
class networkHandler {
constructor() {
this.responseHandler = responseHandler;
this.proxy = proxyRequest;
this.prepareProxy = prepareProxyRequest;
this.processAxiosResponse = processAxiosResponse;
}
}

module.exports = {
networkHandler,
};
158 changes: 158 additions & 0 deletions test/integrations/destinations/rakuten/dataDelivery/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { endpoint, commonOutputHeaders } from '../processor/commonConfig';
const commonParams = {
xml: 1,
amtlist: '12500|12500',
qlist: '|5',
ord: 'SampleOrderId',
tr: 'SampleRanSiteID',
land: '20240129_1200',
};
export const data = [
{
name: 'rakuten',
description: 'Test 0: Failure response from rakuten for invalid mid',
feature: 'dataDelivery',
module: 'destination',
version: 'v0',
input: {
request: {
body: {
method: 'GET',
endpoint,
headers: commonOutputHeaders,
params: {
mid: 'invalid_mid',
...commonParams,
},
userId: '',
},
},
},
output: {
response: {
status: 400,
statTags: {
errorCategory: 'dataValidation',
errorType: 'configuration',
destType: 'RAKUTEN',
module: 'destination',
implementation: 'native',
feature: 'dataDelivery',
destinationId: 'Non-determininable',
workspaceId: 'Non-determininable',
},
destinationResponse: '',
authErrorCategory: '',
message: 'Request failed with status: 400 due to invalid Marketing Id',
},
},
},
{
name: 'rakuten',
description: 'Test 1: Failure response from rakuten for access denied for rakuten mid',
feature: 'dataDelivery',
module: 'destination',
version: 'v0',
input: {
request: {
body: {
method: 'GET',
endpoint,
headers: commonOutputHeaders,
params: {
mid: 'access_denied_for_mid',
...commonParams,
},
userId: '',
},
},
},
output: {
response: {
status: 400,
statTags: {
errorCategory: 'dataValidation',
errorType: 'configuration',
destType: 'RAKUTEN',
module: 'destination',
implementation: 'native',
feature: 'dataDelivery',
destinationId: 'Non-determininable',
workspaceId: 'Non-determininable',
},
destinationResponse: '',
authErrorCategory: '',
message:
'Request failed with status: 200 due to Access denied. Can you try to enable pixel tracking for this mid.',
},
},
},
{
name: 'rakuten',
description: 'Test 2: Failure response from rakuten for bad records>0',
feature: 'dataDelivery',
module: 'destination',
version: 'v0',
input: {
request: {
body: {
method: 'GET',
endpoint,
headers: commonOutputHeaders,
params: {
mid: 'valid_mid_with_bad_records',
...commonParams,
},
userId: '',
},
},
},
output: {
response: {
status: 400,
statTags: {
errorCategory: 'dataValidation',
errorType: 'instrumentation',
destType: 'RAKUTEN',
module: 'destination',
implementation: 'native',
feature: 'dataDelivery',
destinationId: 'Non-determininable',
workspaceId: 'Non-determininable',
},
destinationResponse: '',
authErrorCategory: '',
message: 'Request failed with status: 200 with number of bad records 3',
},
},
},
{
name: 'rakuten',
description: 'Test 3: Success response from rakuten with good records > 0',
feature: 'dataDelivery',
module: 'destination',
version: 'v0',
input: {
request: {
body: {
method: 'GET',
endpoint,
headers: commonOutputHeaders,
params: {
mid: 'valid_mid_with_good_records',
...commonParams,
},
userId: '',
},
},
},
output: {
response: {
status: 200,
destinationResponse:
'<response><unique_id>143407391431</unique_id><summary><transactions><good>3</good><bad>0</bad></transactions></summary></response>',
message: '[RAKUTEN Response Handler] - Request Processed Successfully',
},
},
},
];
94 changes: 94 additions & 0 deletions test/integrations/destinations/rakuten/network.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
export const networkCallsData = [
{
httpReq: {
url: 'https://track.linksynergy.com/ep',
params: {
mid: 'invalid_mid',
xml: 1,
amtlist: '12500|12500',
qlist: '|5',
ord: 'SampleOrderId',
tr: 'SampleRanSiteID',
land: '20240129_1200',
},
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
},
httpRes: {
status: 400,
data: '<!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad Request</title><style type="text/css">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 – Bad Request</h1></body></html>',
},
},
{
httpReq: {
url: 'https://track.linksynergy.com/ep',
params: {
mid: 'access_denied_for_mid',
xml: 1,
amtlist: '12500|12500',
qlist: '|5',
ord: 'SampleOrderId',
tr: 'SampleRanSiteID',
land: '20240129_1200',
},
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
},
httpRes: {
status: 200,
data: '<response><error>Access denied</error></response>',
},
},
{
httpReq: {
url: 'https://track.linksynergy.com/ep',
params: {
mid: 'valid_mid_with_good_records',
xml: 1,
amtlist: '12500|12500',
qlist: '|5',
ord: 'SampleOrderId',
tr: 'SampleRanSiteID',
land: '20240129_1200',
},
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
},
httpRes: {
status: 200,
data: '<response><unique_id>143407391431</unique_id><summary><transactions><good>3</good><bad>0</bad></transactions></summary></response>',
},
},
{
httpReq: {
url: 'https://track.linksynergy.com/ep',
params: {
mid: 'valid_mid_with_bad_records',
xml: 1,
amtlist: '12500|12500',
qlist: '|5',
ord: 'SampleOrderId',
tr: 'SampleRanSiteID',
land: '20240129_1200',
},
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
},
httpRes: {
status: 200,
data: '<response><unique_id>143407391431</unique_id><summary><transactions><good>0</good><bad>3</bad></transactions></summary></response>',
},
},
];
Loading

0 comments on commit f5dd832

Please sign in to comment.