Skip to content

Commit

Permalink
feat: feature flag integration with webhook body format support
Browse files Browse the repository at this point in the history
  • Loading branch information
vinayteki95 committed Dec 10, 2024
1 parent ebcf84e commit 35bec9b
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"editor.formatOnSave": true
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.defaultFormatter": "vscode.typescript-language-features",
"editor.formatOnSave": true
},
"[jsonc]": {
Expand Down
36 changes: 36 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"component-each": "^0.2.6",
"crypto-js": "^4.2.0",
"dotenv": "^16.0.3",
"feature-flag-sdk": "file:../rudder-control-plane/libs/featureflag-sdk-node",
"flat": "^5.0.2",
"form-data": "^4.0.0",
"get-value": "^3.0.1",
Expand Down Expand Up @@ -109,6 +110,7 @@
"parse-static-imports": "^1.1.0",
"prom-client": "^14.2.0",
"qs": "^6.11.1",
"querystring": "^0.2.1",
"rs-jsonpath": "^1.1.2",
"set-value": "^4.1.0",
"sha256": "^0.2.0",
Expand Down
14 changes: 14 additions & 0 deletions src/cdk/v2/destinations/http/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { toXML } = require('jstoxml');
const { groupBy } = require('lodash');
const { createHash } = require('crypto');
const querystring = require('querystring');
const { ConfigurationError } = require('@rudderstack/integrations-lib');
const { BatchUtils } = require('@rudderstack/workflow-engine');
const {
Expand Down Expand Up @@ -84,6 +85,18 @@ const getXMLPayload = (payload) =>
header: true,
});

/**
* Converts JSON payload to application/x-www-form-urlencoded format.
* @param {Object} payload - The JSON payload to be converted.
* @returns {string} - The payload in application/x-www-form-urlencoded format.
*/
const getFORMPayload = (payload) => {
if (!payload) {
throw new ConfigurationError('Invalid payload for FORM format');
}
return querystring.stringify(payload);
}

const getMergedEvents = (batch) => {
const events = [];
batch.forEach((event) => {
Expand Down Expand Up @@ -152,5 +165,6 @@ module.exports = {
addPathParams,
excludeMappedFields,
getXMLPayload,
getFORMPayload,
batchSuccessfulEvents,
};
30 changes: 28 additions & 2 deletions src/cdk/v2/destinations/webhook/procWorkflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ bindings:
- path: ../../bindings/jsontemplate
exportAll: true
- path: ../../../../v0/destinations/webhook/utils
exportAll: true
- name: getHashFromArray
path: ../../../../v0/util
- name: getIntegrationsObj
Expand Down Expand Up @@ -60,7 +61,32 @@ steps:
payload.context.ip = ip;
)
$.context.payload = $.removeUndefinedAndNullValues(payload)
- name: buildResponseForProcessTransformation
- name: buildResponseForProcessTransformationWithBodyFormatting
condition: await $.isFormattedBodyFeatureEnabled(.metadata.workspaceId) === true
template: |
const finalPayload = {
body: {
JSON: {},
JSON_ARRAY: {},
XML: {},
FORM: {},
},
version: '1',
userId: ^.message.anonymousId,
type: 'REST',
method: $.context.method,
endpoint: $.context.finalEndpoint,
headers: $.context.finalHeaders,
params: $.context.params,
files: {},
};
const formattedPayload = $.getFormatedPayload($.context.finalHeaders, $.context.payload);
finalPayload.body[formattedPayload.contentTypeSimplified] = formattedPayload.payload || {};
$.context.payload = finalPayload;
$.context.payload
- name: buildResponseForProcessTransformationWithDefaultBodyFormat
condition: await $.isFormattedBodyFeatureEnabled(.metadata.workspaceId) !== true
template: |
$.context.payload.({
"body": {
Expand All @@ -77,4 +103,4 @@ steps:
"headers": $.context.finalHeaders,
"params": $.context.params,
"files": {}
})
})
1 change: 1 addition & 0 deletions src/cdk/v2/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {

import logger from '../../logger';


const defTags = {
[tags.TAG_NAMES.IMPLEMENTATION]: tags.IMPLEMENTATIONS.CDK_V2,
};
Expand Down
39 changes: 39 additions & 0 deletions src/v0/destinations/webhook/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
const { getXMLPayload, getFORMPayload } = require('../../../cdk/v2/destinations/http/utils');
const { EventType } = require('../../../constants');
const { getFieldValueFromMessage, flattenJson } = require('../../util');
const { isFeatureEnabled, setDefaultTraits } = require('feature-flag-sdk')


const JSON = 'JSON',
XML = 'XML',
FORM = 'FORM';

const ContentTypeConstants = {
'application/json': JSON,
'application/xml': XML,
'text/xml': XML,
'application/x-www-form-urlencoded': FORM
}

const isFormattedBodyFeatureEnabled = async (workspaceId) => {
return await isFeatureEnabled(workspaceId, 'dest_transformer_webhook_form_support');
}

const getFormatedPayload = (headers, payload) => {
const normalizedHeaders = Object.keys(headers).reduce((acc, key) => {
acc[key.toLowerCase()] = headers[key];
return acc;
}, {});
const contentType = normalizedHeaders['content-type'];
const contentTypeSimplified = ContentTypeConstants[contentType] || JSON;

switch (contentTypeSimplified) {
case XML:
return { payload: getXMLPayload(payload), contentTypeSimplified };
case FORM:
return { payload: getFORMPayload(payload), contentTypeSimplified };
default:
return { payload, contentTypeSimplified };
}
};

const getPropertyParams = (message) => {
if (message.type === EventType.IDENTIFY) {
Expand All @@ -10,4 +46,7 @@ const getPropertyParams = (message) => {

module.exports = {
getPropertyParams,
getFormatedPayload,
isFormattedBodyFeatureEnabled,
ContentTypeConstants
};
Loading

0 comments on commit 35bec9b

Please sign in to comment.