n8n/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts
Iván Ovejero e77fd5d286
refactor: Switch plain errors in nodes-base to ApplicationError (no-changelog) (#7914)
Ensure all errors in `nodes-base` are `ApplicationError` or children of
it and contain no variables in the message, to continue normalizing all
the backend errors we report to Sentry. Also, skip reporting to Sentry
errors from user input and from external APIs. In future we should
refine `ApplicationError` to more specific errors.

Follow-up to: [#7877](https://github.com/n8n-io/n8n/pull/7877)

- [x] Test workflows:
https://github.com/n8n-io/n8n/actions/runs/7084627970
- [x] e2e: https://github.com/n8n-io/n8n/actions/runs/7084936861

---------

Co-authored-by: Michael Kret <michael.k@radency.com>
2023-12-05 11:17:08 +01:00

104 lines
3 KiB
TypeScript

import type {
IDataObject,
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IWebhookFunctions,
IHttpRequestOptions,
INodeExecutionData,
} from 'n8n-workflow';
import { ApplicationError, deepCopy } from 'n8n-workflow';
import type { IRequestBody } from './types';
export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: object | IRequestBody,
headers?: object,
): Promise<any> {
const credentials = await this.getCredentials('aws');
const requestOptions = {
qs: {
service,
path,
},
method,
body: JSON.stringify(body),
url: '',
headers,
region: credentials?.region as string,
} as IHttpRequestOptions;
try {
return JSON.parse(
(await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions)) as string,
);
} catch (error) {
const statusCode = (error.statusCode || error.cause?.statusCode) as number;
let errorMessage =
error.response?.body?.message || error.response?.body?.Message || error.message;
if (statusCode === 403) {
if (errorMessage === 'The security token included in the request is invalid.') {
throw new ApplicationError('The AWS credentials are not valid!', { level: 'warning' });
} else if (
errorMessage.startsWith(
'The request signature we calculated does not match the signature you provided',
)
) {
throw new ApplicationError('The AWS credentials are not valid!', { level: 'warning' });
}
}
if (error.cause?.error) {
try {
errorMessage = JSON.parse(error.cause?.error).message;
} catch (ex) {}
}
throw new ApplicationError(`AWS error response [${statusCode}]: ${errorMessage}`, {
level: 'warning',
});
}
}
export async function awsApiRequestAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: IRequestBody,
headers?: object,
): Promise<any> {
const returnData: IDataObject[] = [];
let responseData;
do {
const originalHeaders = Object.assign({}, headers); //The awsapirequest function adds the hmac signature to the headers, if we pass the modified headers back in on the next call it will fail with invalid signature
responseData = await awsApiRequest.call(this, service, method, path, body, originalHeaders);
if (responseData.LastEvaluatedKey) {
body!.ExclusiveStartKey = responseData.LastEvaluatedKey;
}
returnData.push(...(responseData.Items as IDataObject[]));
} while (responseData.LastEvaluatedKey !== undefined);
return returnData;
}
export function copyInputItem(item: INodeExecutionData, properties: string[]): IDataObject {
// Prepare the data to insert and copy it to be returned
const newItem: IDataObject = {};
for (const property of properties) {
if (item.json[property] === undefined) {
newItem[property] = null;
} else {
newItem[property] = deepCopy(item.json[property]);
}
}
return newItem;
}