@@ -195,12 +193,27 @@ export default defineComponent({
return '';
},
isWebhookMethodVisible(webhook: IWebhookDescription): boolean {
+ try {
+ const method = this.workflowHelpers.getWebhookExpressionValue(webhook, 'httpMethod', false);
+ if (Array.isArray(method) && method.length !== 1) {
+ return false;
+ }
+ } catch (error) {}
+
if (typeof webhook.ndvHideMethod === 'string') {
return !this.workflowHelpers.getWebhookExpressionValue(webhook, 'ndvHideMethod');
}
return !webhook.ndvHideMethod;
},
+
+ getWebhookHttpMethod(webhook: IWebhookDescription): string {
+ const method = this.workflowHelpers.getWebhookExpressionValue(webhook, 'httpMethod', false);
+ if (Array.isArray(method)) {
+ return method[0];
+ }
+ return method;
+ },
},
});
diff --git a/packages/editor-ui/src/components/TriggerPanel.vue b/packages/editor-ui/src/components/TriggerPanel.vue
index 8c022a924fbd5..c53ecfc0deda1 100644
--- a/packages/editor-ui/src/components/TriggerPanel.vue
+++ b/packages/editor-ui/src/components/TriggerPanel.vue
@@ -225,10 +225,17 @@ export default defineComponent({
return undefined;
}
- return this.workflowHelpers.getWebhookExpressionValue(
+ const httpMethod = this.workflowHelpers.getWebhookExpressionValue(
this.nodeType.webhooks[0],
'httpMethod',
+ false,
);
+
+ if (Array.isArray(httpMethod)) {
+ return httpMethod.join(', ');
+ }
+
+ return httpMethod;
},
webhookTestUrl(): string | undefined {
if (!this.node || !this.nodeType?.webhooks?.length) {
diff --git a/packages/editor-ui/src/composables/useWorkflowHelpers.ts b/packages/editor-ui/src/composables/useWorkflowHelpers.ts
index 901f6bb122211..6fe5a9490c8f0 100644
--- a/packages/editor-ui/src/composables/useWorkflowHelpers.ts
+++ b/packages/editor-ui/src/composables/useWorkflowHelpers.ts
@@ -737,12 +737,21 @@ export function useWorkflowHelpers(options: { router: ReturnType unknown } | null;
if (proxy?.isProxy && proxy.toJSON) return JSON.stringify(proxy.toJSON());
const workflow = getCurrentWorkflow();
diff --git a/packages/nodes-base/nodes/Webhook/Webhook.node.ts b/packages/nodes-base/nodes/Webhook/Webhook.node.ts
index 31a877941a165..98b699962ac04 100644
--- a/packages/nodes-base/nodes/Webhook/Webhook.node.ts
+++ b/packages/nodes-base/nodes/Webhook/Webhook.node.ts
@@ -74,7 +74,60 @@ export class Webhook extends Node {
credentials: credentialsProperty(this.authPropertyName),
webhooks: [defaultWebhookDescription],
properties: [
- httpMethodsProperty,
+ {
+ displayName: 'Allow Multiple HTTP Methods',
+ name: 'multipleMethods',
+ type: 'boolean',
+ default: false,
+ isNodeSetting: true,
+ description: 'Whether to allow the webhook to listen for multiple HTTP methods',
+ },
+ {
+ ...httpMethodsProperty,
+ displayOptions: {
+ show: {
+ multipleMethods: [false],
+ },
+ },
+ },
+ {
+ displayName: 'HTTP Methods',
+ name: 'httpMethod',
+ type: 'multiOptions',
+ options: [
+ {
+ name: 'DELETE',
+ value: 'DELETE',
+ },
+ {
+ name: 'GET',
+ value: 'GET',
+ },
+ {
+ name: 'HEAD',
+ value: 'HEAD',
+ },
+ {
+ name: 'PATCH',
+ value: 'PATCH',
+ },
+ {
+ name: 'POST',
+ value: 'POST',
+ },
+ {
+ name: 'PUT',
+ value: 'PUT',
+ },
+ ],
+ default: ['GET', 'POST'],
+ description: 'The HTTP methods to listen to',
+ displayOptions: {
+ show: {
+ multipleMethods: [true],
+ },
+ },
+ },
{
displayName: 'Path',
name: 'path',
@@ -144,6 +197,7 @@ export class Webhook extends Node {
};
const req = context.getRequestObject();
const resp = context.getResponseObject();
+ const requestMethod = context.getRequestObject().method;
if (!isIpWhitelisted(options.ipWhitelist, req.ips, req.ip)) {
resp.writeHead(403);
@@ -165,7 +219,7 @@ export class Webhook extends Node {
throw error;
}
- const prepareOutput = setupOutputConnection(context, {
+ const prepareOutput = setupOutputConnection(context, requestMethod, {
jwtPayload: validationData,
});
diff --git a/packages/nodes-base/nodes/Webhook/utils.ts b/packages/nodes-base/nodes/Webhook/utils.ts
index 1bf6b8407e451..33fd36331ecc8 100644
--- a/packages/nodes-base/nodes/Webhook/utils.ts
+++ b/packages/nodes-base/nodes/Webhook/utils.ts
@@ -50,22 +50,34 @@ export const getResponseData = (parameters: WebhookParameters) => {
};
export const configuredOutputs = (parameters: WebhookParameters) => {
- const httpMethod = parameters.httpMethod;
+ const httpMethod = parameters.httpMethod as string | string[];
- return [
- {
+ if (!Array.isArray(httpMethod))
+ return [
+ {
+ type: `${NodeConnectionType.Main}`,
+ displayName: httpMethod,
+ },
+ ];
+
+ const outputs = httpMethod.map((method) => {
+ return {
type: `${NodeConnectionType.Main}`,
- displayName: httpMethod,
- },
- ];
+ displayName: method,
+ };
+ });
+
+ return outputs;
};
export const setupOutputConnection = (
ctx: IWebhookFunctions,
+ method: string,
additionalData: {
jwtPayload?: IDataObject;
},
) => {
+ const httpMethod = ctx.getNodeParameter('httpMethod', []) as string[] | string;
let webhookUrl = ctx.getNodeWebhookUrl('default') as string;
const executionMode = ctx.getMode() === 'manual' ? 'test' : 'production';
@@ -73,13 +85,29 @@ export const setupOutputConnection = (
webhookUrl = webhookUrl.replace('/webhook/', '/webhook-test/');
}
+ // multi methods could be set in settings of node, so we need to check if it's an array
+ if (!Array.isArray(httpMethod)) {
+ return (outputData: INodeExecutionData): INodeExecutionData[][] => {
+ outputData.json.webhookUrl = webhookUrl;
+ outputData.json.executionMode = executionMode;
+ if (additionalData?.jwtPayload) {
+ outputData.json.jwtPayload = additionalData.jwtPayload;
+ }
+ return [[outputData]];
+ };
+ }
+
+ const outputIndex = httpMethod.indexOf(method.toUpperCase());
+ const outputs: INodeExecutionData[][] = httpMethod.map(() => []);
+
return (outputData: INodeExecutionData): INodeExecutionData[][] => {
outputData.json.webhookUrl = webhookUrl;
outputData.json.executionMode = executionMode;
if (additionalData?.jwtPayload) {
outputData.json.jwtPayload = additionalData.jwtPayload;
}
- return [[outputData]];
+ outputs[outputIndex] = [outputData];
+ return outputs;
};
};
diff --git a/packages/workflow/src/NodeHelpers.ts b/packages/workflow/src/NodeHelpers.ts
index 8a097c2a9122b..06a405f9e8916 100644
--- a/packages/workflow/src/NodeHelpers.ts
+++ b/packages/workflow/src/NodeHelpers.ts
@@ -996,7 +996,7 @@ export function getNodeWebhooks(
) as boolean;
const path = getNodeWebhookPath(workflowId, node, nodeWebhookPath, isFullPath, restartWebhook);
- const httpMethod = workflow.expression.getSimpleParameterValue(
+ const webhookMethods = workflow.expression.getSimpleParameterValue(
node,
webhookDescription.httpMethod,
mode,
@@ -1005,7 +1005,7 @@ export function getNodeWebhooks(
'GET',
);
- if (httpMethod === undefined) {
+ if (webhookMethods === undefined) {
// TODO: Use a proper logger
console.error(
`The webhook "${path}" for node "${node.name}" in workflow "${workflowId}" could not be added because the httpMethod is not defined.`,
@@ -1018,15 +1018,20 @@ export function getNodeWebhooks(
webhookId = node.webhookId;
}
- returnData.push({
- httpMethod: httpMethod.toString() as IHttpRequestMethods,
- node: node.name,
- path,
- webhookDescription,
- workflowId,
- workflowExecuteAdditionalData: additionalData,
- webhookId,
- });
+ String(webhookMethods)
+ .split(',')
+ .forEach((httpMethod) => {
+ if (!httpMethod) return;
+ returnData.push({
+ httpMethod: httpMethod.trim() as IHttpRequestMethods,
+ node: node.name,
+ path,
+ webhookDescription,
+ workflowId,
+ workflowExecuteAdditionalData: additionalData,
+ webhookId,
+ });
+ });
}
return returnData;