diff --git a/packages/nodes-base/credentials/PeekalinkApi.credentials.ts b/packages/nodes-base/credentials/PeekalinkApi.credentials.ts new file mode 100644 index 0000000000..5d4edf3f62 --- /dev/null +++ b/packages/nodes-base/credentials/PeekalinkApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class PeekalinkApi implements ICredentialType { + name = 'peekalinkApi'; + displayName = 'Peekalink API'; + documentationUrl = 'peekalink'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts b/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts new file mode 100644 index 0000000000..8e1c339fd7 --- /dev/null +++ b/packages/nodes-base/nodes/Peekalink/GenericFunctions.ts @@ -0,0 +1,47 @@ +import { + OptionsWithUri, +} from 'request'; + +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { + IDataObject, +} from 'n8n-workflow'; + +export async function peekalinkApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + try { + const credentials = this.getCredentials('peekalinkApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + let options: OptionsWithUri = { + headers: { + 'X-API-Key': credentials.apiKey, + }, + method, + qs, + body, + uri: uri || `https://api.peekalink.io${resource}`, + json: true, + }; + + options = Object.assign({}, options, option); + + return await this.helpers.request!(options); + } catch (error) { + + if (error.response && error.response.body && error.response.body.message) { + // Try to return the error prettier + const errorBody = error.response.body; + throw new Error(`Peekalink error response [${error.statusCode}]: ${errorBody.message}`); + } + + // Expected error data did not get returned so throw the actual error + throw error; + } +} diff --git a/packages/nodes-base/nodes/Peekalink/Peekalink.node.ts b/packages/nodes-base/nodes/Peekalink/Peekalink.node.ts new file mode 100644 index 0000000000..adcaf4c907 --- /dev/null +++ b/packages/nodes-base/nodes/Peekalink/Peekalink.node.ts @@ -0,0 +1,101 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +import { + peekalinkApiRequest, +} from './GenericFunctions'; + +export class Peekalink implements INodeType { + description: INodeTypeDescription = { + displayName: 'Peekalink', + name: 'peekalink', + icon: 'file:peekalink.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"]', + description: 'Consume the Peekalink API', + defaults: { + name: 'Peekalink', + color: '#00ade8', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'peekalinkApi', + required: true, + }, + ], + properties: [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + options: [ + { + name: 'Is available', + value: 'isAvailable', + description: 'Check whether preview for a given link is available', + }, + { + name: 'Preview', + value: 'preview', + description: 'Return the preview for a link', + }, + ], + default: 'preview', + description: 'The operation to perform.', + }, + { + displayName: 'URL', + name: 'url', + type: 'string', + default: '', + description: '', + required: true, + }, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + const qs: IDataObject = {}; + let responseData; + const operation = this.getNodeParameter('operation', 0) as string; + + for (let i = 0; i < length; i++) { + if (operation === 'isAvailable') { + const url = this.getNodeParameter('url', i) as string; + const body: IDataObject = { + link: url, + }; + + responseData = await peekalinkApiRequest.call(this, 'POST', `/is-available/`, body); + } + if (operation === 'preview') { + const url = this.getNodeParameter('url', i) as string; + const body: IDataObject = { + link: url, + }; + + responseData = await peekalinkApiRequest.call(this, 'POST', `/`, body); + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Peekalink/peekalink.png b/packages/nodes-base/nodes/Peekalink/peekalink.png new file mode 100644 index 0000000000..dc2e8426ff Binary files /dev/null and b/packages/nodes-base/nodes/Peekalink/peekalink.png differ diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 851e13e54e..30f82f133c 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -164,6 +164,7 @@ "dist/credentials/PagerDutyApi.credentials.js", "dist/credentials/PagerDutyOAuth2Api.credentials.js", "dist/credentials/PayPalApi.credentials.js", + "dist/credentials/PeekalinkApi.credentials.js", "dist/credentials/PhantombusterApi.credentials.js", "dist/credentials/PipedriveApi.credentials.js", "dist/credentials/PipedriveOAuth2Api.credentials.js", @@ -410,6 +411,7 @@ "dist/nodes/PagerDuty/PagerDuty.node.js", "dist/nodes/PayPal/PayPal.node.js", "dist/nodes/PayPal/PayPalTrigger.node.js", + "dist/nodes/Peekalink/Peekalink.node.js", "dist/nodes/Phantombuster/Phantombuster.node.js", "dist/nodes/Pipedrive/Pipedrive.node.js", "dist/nodes/Pipedrive/PipedriveTrigger.node.js",