Skip to content

Commit

Permalink
feat: add new stat for access token expired in fb custom audience (#3043
Browse files Browse the repository at this point in the history
)

* feat: initial commit

* fix: initial commit

* fix: adding unauthorized error for access token failure

* fix: reviw comments addressed

* feat: reviw comments addressed

* fix: changing version of integrations lib

* Apply suggestions from code review

Co-authored-by: Sankeerth <[email protected]>

* fix: review comments addressed

* fix: removing unnecessary tag

* fix: removing unnecessary log

* fix: review comments addressed

* fix: adding destination response

* Update src/v0/util/facebookUtils/networkHandler.js

Co-authored-by: Sankeerth <[email protected]>

---------

Co-authored-by: Sankeerth <[email protected]>
  • Loading branch information
shrouti1507 and sanpj2292 authored Feb 2, 2024
1 parent 5ee1b7c commit 1e6d540
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 23 deletions.
46 changes: 41 additions & 5 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"@koa/router": "^12.0.0",
"@ndhoule/extend": "^2.0.0",
"@pyroscope/nodejs": "^0.2.6",
"@rudderstack/integrations-lib": "^0.1.8",
"@rudderstack/integrations-lib": "^0.2.2",
"@rudderstack/workflow-engine": "^0.6.9",
"ajv": "^8.12.0",
"ajv-draft-04": "^1.0.0",
Expand Down
16 changes: 15 additions & 1 deletion src/util/error-extractor/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
/* eslint-disable max-classes-per-file */
import { MessageDetails, StatusCode } from "./types";
import { MessageDetails, StatusCode, Stat } from "./types";

export class ErrorDetailsExtractor {
status: StatusCode;

messageDetails: MessageDetails;

stat : Stat

constructor (builder: ErrorDetailsExtractorBuilder) {
this.status = builder.getStatus();
this.messageDetails = builder.getMessageDetails();
this.stat = builder.getStat();
}

}
Expand All @@ -18,16 +21,23 @@ export class ErrorDetailsExtractorBuilder {

messageDetails: MessageDetails;

stat: Stat;
constructor() {
this.status = 0;
this.messageDetails = {};
this.stat = {};
}

setStatus(status: number): ErrorDetailsExtractorBuilder {
this.status = status;
return this;
}

setStat(stat: Record<string, string>): ErrorDetailsExtractorBuilder {
this.stat = stat
return this;
}

/**
* This means we need to set a message from a specific field that we see from the destination's response
*
Expand Down Expand Up @@ -69,6 +79,10 @@ export class ErrorDetailsExtractorBuilder {
getStatus(): number {
return this.status;
}

getStat(): Record<string, string> {
return this.stat;
}

getMessageDetails(): Record<string, string> {
return this.messageDetails;
Expand Down
3 changes: 2 additions & 1 deletion src/util/error-extractor/types.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export type MessageDetails = Record<string, string>;
export type StatusCode = number;
export type StatusCode = number;
export type Stat = Record<string, string>
38 changes: 32 additions & 6 deletions src/v0/util/facebookUtils/networkHandler.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
const { isEmpty } = require('lodash');
const get = require('get-value');
const { NetworkError } = require('@rudderstack/integrations-lib');
const {
NetworkError,
ConfigurationAuthError,
isDefinedAndNotNull,
ERROR_TYPES,
TAG_NAMES,
METADATA,
} = require('@rudderstack/integrations-lib');
const {
processAxiosResponse,
getDynamicErrorType,
} = require('../../../adapters/utils/networkUtils');
const { prepareProxyRequest, proxyRequest } = require('../../../adapters/network');
const tags = require('../tags');
const { ErrorDetailsExtractorBuilder } = require('../../../util/error-extractor');

/**
Expand Down Expand Up @@ -100,12 +106,26 @@ const errorDetailsMap = {
190: {
460: new ErrorDetailsExtractorBuilder()
.setStatus(400)
.setStat({
[TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH,
})
.setMessage(
'The session has been invalidated because the user changed their password or Facebook has changed the session for security reasons',
)
.build(),

463: new ErrorDetailsExtractorBuilder()
.setStatus(400)
.setStat({
[TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH,
})
.setMessageField('message')
.build(),
default: new ErrorDetailsExtractorBuilder()
.setStatus(400)
.setStat({
[TAG_NAMES.ERROR_TYPE]: ERROR_TYPES.AUTH,
})
.setMessage('Invalid OAuth 2.0 access token')
.build(),
},
Expand Down Expand Up @@ -217,7 +237,7 @@ const getStatus = (error) => {
// Unhandled error response
return {
status: errorStatus,
tags: { [tags.TAG_NAMES.META]: tags.METADATA.UNHANDLED_STATUS_CODE },
stats: { [TAG_NAMES.META]: METADATA.UNHANDLED_STATUS_CODE },
};
}
errorStatus = errorDetail.status;
Expand All @@ -227,7 +247,7 @@ const getStatus = (error) => {
errorMessage = get(error, errorDetail?.messageDetails?.field);
}

return { status: errorStatus, errorMessage };
return { status: errorStatus, errorMessage, stats: errorDetail?.stat };
};

const errorResponseHandler = (destResponse) => {
Expand All @@ -237,13 +257,19 @@ const errorResponseHandler = (destResponse) => {
return;
}
const { error } = response;
const { status, errorMessage, tags: errorStatTags } = getStatus(error);
const { status, errorMessage, stats: errorStatTags } = getStatus(error);
if (
isDefinedAndNotNull(errorStatTags) &&
errorStatTags?.[TAG_NAMES.ERROR_TYPE] === ERROR_TYPES.AUTH
) {
throw new ConfigurationAuthError(errorMessage, { ...response, status: destResponse.status });
}
throw new NetworkError(
`${errorMessage || error.message || 'Unknown failure during response transformation'}`,
status,
{
...errorStatTags,
[tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
[TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
},
{ ...response, status: destResponse.status },
);
Expand Down
2 changes: 1 addition & 1 deletion src/v0/util/tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const ERROR_TYPES = {
OAUTH_SECRET: 'oAuthSecret',
UNSUPPORTED: 'unsupported',
REDIS: 'redis',
FILTERED: 'filtered',
FILTERED: 'filtered'
};

const METADATA = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,20 @@ export const data = [
message: 'Invalid OAuth 2.0 access token',
destinationResponse: {
error: {
message: 'The access token could not be decrypted',
type: 'OAuthException',
code: 190,
fbtrace_id: 'fbpixel_trace_id',
message: 'The access token could not be decrypted',
type: 'OAuthException',
},
status: 500,
},
statTags: {
destType: 'FACEBOOK_PIXEL',
errorCategory: 'network',
errorCategory: 'dataValidation',
destinationId: 'Non-determininable',
workspaceId: 'Non-determininable',
errorType: 'aborted',
errorType: 'configuration',
meta: 'accessTokenExpired',
feature: 'dataDelivery',
implementation: 'native',
module: 'destination',
Expand Down
9 changes: 5 additions & 4 deletions test/integrations/destinations/fb/dataDelivery/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,20 @@ export const data = [
message: 'Invalid OAuth 2.0 access token',
destinationResponse: {
error: {
message: 'The access token could not be decrypted',
type: 'OAuthException',
code: 190,
fbtrace_id: 'fbpixel_trace_id',
message: 'The access token could not be decrypted',
type: 'OAuthException',
},
status: 500,
},
statTags: {
destType: 'FB',
errorCategory: 'network',
errorCategory: 'dataValidation',
destinationId: 'Non-determininable',
workspaceId: 'Non-determininable',
errorType: 'aborted',
errorType: 'configuration',
meta: 'accessTokenExpired',
feature: 'dataDelivery',
implementation: 'native',
module: 'destination',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,4 +572,76 @@ export const data = [
},
},
},
{
name: 'fb_custom_audience',
description: 'user addition failed due expired access token error',
feature: 'dataDelivery',
module: 'destination',
version: 'v0',
input: {
request: {
body: {
version: '1',
type: 'REST',
method: 'DELETE',
endpoint: getEndPoint('aud1'),
headers: {
'test-dest-response-key': 'accessTokenInvalidError',
},
params: {
access_token: 'ABC',
payload: {
is_raw: true,
data_source: {
sub_type: 'ANYTHING',
},
schema: ['DOBY', 'PHONE', 'GEN', 'FI', 'MADID', 'ZIP', 'ST', 'COUNTRY'],
data: [['2013', '@09432457768', 'f', 'Ms.', 'ABC', 'ZIP ', '123abc ', 'IN']],
},
},
body: {
JSON: {},
XML: {},
JSON_ARRAY: {},
FORM: {},
},
files: {},
},
},
},
output: {
response: {
status: 400,
body: {
output: {
destinationResponse: {
error: {
code: 190,
error_subcode: 463,
fbtrace_id: 'A3b8C6PpI-kdIOwPwV4PANi',
message:
'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.',
type: 'OAuthException',
},
status: 400,
},
message:
'Error validating access token: Session has expired on Tuesday, 01-Aug-23 10:12:14 PDT. The current time is Sunday, 28-Jan-24 16:01:17 PST.',
statTags: {
destType: 'FB_CUSTOM_AUDIENCE',
destinationId: 'Non-determininable',
errorCategory: 'dataValidation',
errorType: 'configuration',
meta: 'accessTokenExpired',
feature: 'dataDelivery',
implementation: 'native',
module: 'destination',
workspaceId: 'Non-determininable',
},
status: 400,
},
},
},
},
},
];
Loading

0 comments on commit 1e6d540

Please sign in to comment.