n8n/packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts
Iván Ovejero 9118e090e7
Add AWS DynamoDB node (#1602)
* dynamodb: request item

* dynamodb: query database

* dynamodb: scans table

* dynamodb: typehints in decodeItem

* dynamodb: recursively decodes map and lists

* dynamodb: cleanup interface, using additional-fields collection

* dynamodb: using fixedCollection for ExpressionAttributeValues

* dynamodb: converts spaces to tabs

* dynamodb: scans with FilterExpression

* dynamodb: fixes tslint

*  Refactor node

* 🔨 Refactor into separate dir

*  Add table name loader

* ✏️ Update operation descriptions

*  Add partition key name param to delete

*  Add params to get operation

* 🔨 Refactor get operation per feedback

*  Refactor for consistency

*  Add createUpdate operation

* aja

* asasa

* aja

* aja

* aja

*  Improvements

*  Lint node

*  Lint description

* 🔥 Remove unused option

*  Apply David's feedback

* ✏️ Add descriptions for specific attributes

* 🔨 Rename return values

* Implement define and automap

*  Minior changes

Co-authored-by: Michael Hirschler <michael.vhirsch@gmail.com>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2021-07-17 14:14:12 +02:00

109 lines
3.3 KiB
TypeScript

import {
URL,
} from 'url';
import {
sign,
} from 'aws4';
import {
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IWebhookFunctions,
} from 'n8n-core';
import {
ICredentialDataDecryptedObject,
IDataObject,
INodeExecutionData,
} from 'n8n-workflow';
import {
IRequestBody,
} from './types';
function getEndpointForService(service: string, credentials: ICredentialDataDecryptedObject): string {
let endpoint;
if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint;
} else if (service === 'sns' && credentials.snsEndpoint) {
endpoint = credentials.snsEndpoint;
} else {
endpoint = `https://${service}.${credentials.region}.amazonaws.com`;
}
return (endpoint as string).replace('{region}', credentials.region as string);
}
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: object | IRequestBody, headers?: object): Promise<any> { // tslint:disable-line:no-any
const credentials = this.getCredentials('aws');
if (credentials === undefined) {
throw new Error('No credentials got returned!');
}
// Concatenate path and instantiate URL object so it parses correctly query strings
const endpoint = new URL(getEndpointForService(service, credentials) + path);
const options = sign({
uri: endpoint,
service,
region: credentials.region,
method,
path: '/',
headers: { ...headers },
body: JSON.stringify(body),
}, {
accessKeyId: credentials.accessKeyId,
secretAccessKey: credentials.secretAccessKey,
});
try {
return JSON.parse(await this.helpers.request!(options));
} catch (error) {
const errorMessage = (error.response && error.response.body.message) || (error.response && error.response.body.Message) || error.message;
if (error.statusCode === 403) {
if (errorMessage === 'The security token included in the request is invalid.') {
throw new Error('The AWS credentials are not valid!');
} else if (errorMessage.startsWith('The request signature we calculated does not match the signature you provided')) {
throw new Error('The AWS credentials are not valid!');
}
}
throw new Error(`AWS error response [${error.statusCode}]: ${errorMessage}`);
}
}
export async function awsApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: IRequestBody, headers?: object): Promise<any> { // tslint:disable-line:no-any
const returnData: IDataObject[] = [];
let responseData;
do {
responseData = await awsApiRequest.call(this, service, method, path, body, headers);
if (responseData.LastEvaluatedKey) {
body!.ExclusiveStartKey = responseData.LastEvaluatedKey;
}
returnData.push(...responseData.Items);
} 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
let newItem: IDataObject;
newItem = {};
for (const property of properties) {
if (item.json[property] === undefined) {
newItem[property] = null;
} else {
newItem[property] = JSON.parse(JSON.stringify(item.json[property]));
}
}
return newItem;
}