diff --git a/packages/nodes-base/credentials/DhlApi.credentials.ts b/packages/nodes-base/credentials/DhlApi.credentials.ts new file mode 100644 index 0000000000..e03b9931b9 --- /dev/null +++ b/packages/nodes-base/credentials/DhlApi.credentials.ts @@ -0,0 +1,18 @@ +import { + ICredentialType, + INodeProperties, +} from 'n8n-workflow'; + +export class DhlApi implements ICredentialType { + name = 'dhlApi'; + displayName = 'DHL API'; + documentationUrl = 'dhl'; + properties: INodeProperties[] = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string', + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Dhl/Dhl.node.ts b/packages/nodes-base/nodes/Dhl/Dhl.node.ts new file mode 100644 index 0000000000..a27966645e --- /dev/null +++ b/packages/nodes-base/nodes/Dhl/Dhl.node.ts @@ -0,0 +1,162 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + ICredentialDataDecryptedObject, + ICredentialsDecrypted, + ICredentialTestFunctions, + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, + NodeCredentialTestResult, +} from 'n8n-workflow'; + +import { + dhlApiRequest, + validateCrendetials, +} from './GenericFunctions'; + +export class Dhl implements INodeType { + description: INodeTypeDescription = { + displayName: 'DHL', + name: 'dhl', + icon: 'file:dhl.svg', + group: ['input'], + version: 1, + subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', + description: 'Consume DHL API', + defaults: { + name: 'DHL', + color: '#fecc00', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'dhlApi', + required: true, + testedBy: 'dhlApiCredentialTest', + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + noDataExpression: true, + type: 'hidden', + options: [ + { + name: 'Shipment', + value: 'shipment', + }, + ], + default: 'shipment', + }, + { + displayName: 'Operation', + name: 'operation', + type: 'options', + noDataExpression: true, + displayOptions: { + show: { + resource: [ + 'shipment', + ], + }, + }, + options: [ + { + name: 'Get Tracking Details', + value: 'get', + }, + ], + default: 'get', + }, + { + displayName: 'Tracking Number', + name: 'trackingNumber', + type: 'string', + required: true, + default: '', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: `Recipient's Postal Code`, + name: 'recipientPostalCode', + type: 'string', + default: '', + description: `DHL will return more detailed information on the shipment when you provide the Recipient's Postal Code - it acts as a verification step`, + }, + ], + }, + ], + }; + + methods = { + credentialTest: { + async dhlApiCredentialTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise { + try { + await validateCrendetials.call(this, credential.data as ICredentialDataDecryptedObject); + } catch (error) { + if (error.statusCode === 401) { + return { + status: 'Error', + message: 'The API Key included in the request is invalid', + }; + } + } + + return { + status: 'OK', + message: 'Connection successful!', + }; + }, + }, + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + let qs: IDataObject = {}; + let responseData; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + + for (let i = 0; i < items.length; i++) { + try { + if (resource === 'shipment') { + if (operation === 'get') { + + const trackingNumber = this.getNodeParameter('trackingNumber', i) as string; + const options = this.getNodeParameter('options', i) as IDataObject; + + qs = { + trackingNumber, + }; + + Object.assign(qs, options); + + responseData = await dhlApiRequest.call(this, 'GET', `/track/shipments`, {}, qs); + + returnData.push(...responseData.shipments); + } + } + } catch (error) { + if (this.continueOnFail()) { + returnData.push({ error: error.description }); + continue; + } + throw error; + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Dhl/GenericFunctions.ts b/packages/nodes-base/nodes/Dhl/GenericFunctions.ts new file mode 100644 index 0000000000..974da39e54 --- /dev/null +++ b/packages/nodes-base/nodes/Dhl/GenericFunctions.ts @@ -0,0 +1,65 @@ +import { + OptionsWithUri, +} from 'request'; + +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { + ICredentialDataDecryptedObject, + ICredentialTestFunctions, + IDataObject, + NodeApiError, +} from 'n8n-workflow'; + +export async function dhlApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const credentials = await this.getCredentials('dhlApi') as { apiKey: string }; + + let options: OptionsWithUri = { + headers: { + 'DHL-API-Key': credentials.apiKey, + }, + method, + qs, + body, + uri: uri || `https://api-eu.dhl.com${path}`, + json: true, + }; + options = Object.assign({}, options, option); + if (Object.keys(options.body).length === 0) { + delete options.body; + } + + try { + return await this.helpers.request!(options); + } catch (error) { + throw new NodeApiError(this.getNode(), error); + } +} + +export async function validateCrendetials(this: ICredentialTestFunctions, decryptedCredentials: ICredentialDataDecryptedObject): Promise { // tslint:disable-line:no-any + const credentials = decryptedCredentials; + + const { apiKey } = credentials as { + apiKey: string, + }; + + const options: OptionsWithUri = { + headers: { + 'DHL-API-Key': apiKey, + }, + qs: { + trackingNumber: 123, + }, + method: 'GET', + uri: `https://api-eu.dhl.com/track/shipments`, + json: true, + }; + + return this.helpers.request!(options); +} diff --git a/packages/nodes-base/nodes/Dhl/dhl.svg b/packages/nodes-base/nodes/Dhl/dhl.svg new file mode 100644 index 0000000000..854e589d3c --- /dev/null +++ b/packages/nodes-base/nodes/Dhl/dhl.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 50d9a0bbce..e1dc5c1b32 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -71,6 +71,7 @@ "dist/credentials/CustomerIoApi.credentials.js", "dist/credentials/DeepLApi.credentials.js", "dist/credentials/DemioApi.credentials.js", + "dist/credentials/DhlApi.credentials.js", "dist/credentials/DiscourseApi.credentials.js", "dist/credentials/DisqusApi.credentials.js", "dist/credentials/DriftApi.credentials.js", @@ -374,6 +375,7 @@ "dist/nodes/DateTime/DateTime.node.js", "dist/nodes/DeepL/DeepL.node.js", "dist/nodes/Demio/Demio.node.js", + "dist/nodes/Dhl/Dhl.node.js", "dist/nodes/Discord/Discord.node.js", "dist/nodes/Discourse/Discourse.node.js", "dist/nodes/Disqus/Disqus.node.js",