diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index 25bbaa43d1..be5b41f808 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -20,6 +20,7 @@ import { } from 'n8n-core'; import { + IDataObject, IExecuteData, IGetExecutePollFunctions, IGetExecuteTriggerFunctions, @@ -117,23 +118,28 @@ export class ActiveWorkflowRunner { } let webhook = await Db.collections.Webhook?.findOne({ webhookPath: path, method: httpMethod }) as IWebhookDb; - let webhookId: string; + let webhookId: string | undefined; if (webhook === undefined) { + // check if a dynamic webhook path exists const pathElements = path.split('/'); - webhookId = pathElements[0]; + webhookId = pathElements.shift(); webhook = await Db.collections.Webhook?.findOne({ webhookId, method: httpMethod }) as IWebhookDb; - // write params to req.params - } - - // check if something exist - if (webhook === undefined) { - // The requested webhook is not registered - throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404); - } - - if (webhookId) { - path = webhook.webhookPath; + if (webhook) { + path = webhook.webhookPath; + // extracting params from path + const webhookPathParams: IDataObject = {}; + webhook.webhookPath.split('/').forEach((ele, index) => { + if (ele.startsWith(':')) { + webhookPathParams[ele.slice(1)] = pathElements[index]; + } + }); + // write params to req.params + Object.assign(req.params, webhookPathParams); + } else { + // The requested webhook is not registered + throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404); + } } const workflowData = await Db.collections.Workflow!.findOne(webhook.workflowId); @@ -265,10 +271,14 @@ export class ActiveWorkflowRunner { method: webhookData.httpMethod, } as IWebhookDb; - if (webhook.webhookPath.includes('/:') && node.webhookId) { + if ((path.startsWith(':') || path.includes('/:')) && node.webhookId) { webhook.webhookId = node.webhookId; } + if (webhook.webhookPath.charAt(0) === '/') { + webhook.webhookPath = webhook.webhookPath.slice(1); + } + try { await Db.collections.Webhook?.insert(webhook); diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index e6bcbd24cb..3ad9b2477b 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -993,6 +993,12 @@ export function getExecuteWebhookFunctions(workflow: Workflow, node: INode, addi return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, fallbackValue); }, + getParamsData(): object { + if (additionalData.httpRequest === undefined) { + throw new Error('Request is missing!'); + } + return additionalData.httpRequest.params; + }, getQueryData(): object { if (additionalData.httpRequest === undefined) { throw new Error('Request is missing!'); diff --git a/packages/node-dev/templates/webhook/simple.ts b/packages/node-dev/templates/webhook/simple.ts index ab81ca51d2..650d843178 100644 --- a/packages/node-dev/templates/webhook/simple.ts +++ b/packages/node-dev/templates/webhook/simple.ts @@ -54,9 +54,10 @@ export class ClassNameReplace implements INodeType { const returnData: IDataObject[] = []; returnData.push( { - body: this.getBodyData(), headers: this.getHeaderData(), + params: this.getParamsData(), query: this.getQueryData(), + body: this.getBodyData(), } ); diff --git a/packages/nodes-base/nodes/Webhook.node.ts b/packages/nodes-base/nodes/Webhook.node.ts index aba5afd12f..268a466246 100644 --- a/packages/nodes-base/nodes/Webhook.node.ts +++ b/packages/nodes-base/nodes/Webhook.node.ts @@ -412,9 +412,10 @@ export class Webhook implements INodeType { const returnItem: INodeExecutionData = { binary: {}, json: { - body: data, headers, + params: this.getParamsData(), query: this.getQueryData(), + body: data, }, }; @@ -458,9 +459,10 @@ export class Webhook implements INodeType { const returnItem: INodeExecutionData = { binary: {}, json: { - body: this.getBodyData(), headers, + params: this.getParamsData(), query: this.getQueryData(), + body: this.getBodyData(), }, }; @@ -483,9 +485,10 @@ export class Webhook implements INodeType { const response: INodeExecutionData = { json: { - body: this.getBodyData(), headers, + params: this.getParamsData(), query: this.getQueryData(), + body: this.getBodyData(), }, }; diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index fec5aa3729..6630a559cd 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -311,6 +311,7 @@ export interface IWebhookFunctions { getNode(): INode; getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any getNodeWebhookUrl: (name: string) => string | undefined; + getParamsData(): object; getQueryData(): object; getRequestObject(): express.Request; getResponseObject(): express.Response; diff --git a/packages/workflow/src/NodeHelpers.ts b/packages/workflow/src/NodeHelpers.ts index 9ab15fea5f..3082b5d3dd 100644 --- a/packages/workflow/src/NodeHelpers.ts +++ b/packages/workflow/src/NodeHelpers.ts @@ -883,7 +883,7 @@ export function getNodeWebhookPath(workflowId: string, node: INode, path: string * @returns {string} */ export function getNodeWebhookUrl(baseUrl: string, workflowId: string, node: INode, path: string, isFullPath?: boolean): string { - if (path.includes('/:') && node.webhookId) { + if ((path.startsWith(':') || path.includes('/:')) && node.webhookId) { // setting this to false to prefix the webhookId isFullPath = false; }