Skip to content

Commit

Permalink
feat(Webhook Node): Overhaul (#8889)
Browse files Browse the repository at this point in the history
Co-authored-by: Giulio Andreini <andreini@netseven.it>
  • Loading branch information
michael-radency and gandreini committed Mar 28, 2024
1 parent 519f945 commit e84c27c
Show file tree
Hide file tree
Showing 17 changed files with 781 additions and 44 deletions.
9 changes: 4 additions & 5 deletions cypress/e2e/16-webhook-node.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ const simpleWebhookCall = (options: SimpleWebhookCallOptions) => {
}

if (responseCode) {
cy.getByTestId('parameter-input-responseCode')
.find('.parameter-input')
.find('input')
.clear()
.type(responseCode.toString());
cy.get('.param-options').click();
getVisibleSelect().contains('Response Code').click();
cy.get('.parameter-item-wrapper > .parameter-input-list-wrapper').children().click();
getVisibleSelect().contains('201').click();
}

if (respondWith) {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/AbstractServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ export abstract class AbstractServer {

private async setupHealthCheck() {
// health check should not care about DB connections
this.app.get('/healthz', async (req, res) => {
this.app.get('/healthz', async (_req, res) => {
res.send({ status: 'ok' });
});

const { connectionState } = Db;
this.app.use((req, res, next) => {
this.app.use((_req, res, next) => {
if (connectionState.connected) {
if (connectionState.migrated) next();
else res.send('n8n is starting up. Please wait');
Expand Down
32 changes: 25 additions & 7 deletions packages/cli/src/WebhookHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,22 @@ export const webhookRequestHandler =
const options = await webhookManager.findAccessControlOptions(path, requestedMethod);
const { allowedOrigins } = options ?? {};

res.header(
'Access-Control-Allow-Origin',
!allowedOrigins || allowedOrigins === '*' ? req.headers.origin : allowedOrigins,
);
if (allowedOrigins && allowedOrigins !== '*' && allowedOrigins !== req.headers.origin) {
const originsList = allowedOrigins.split(',');
const defaultOrigin = originsList[0];

if (originsList.length === 1) {
res.header('Access-Control-Allow-Origin', defaultOrigin);
}

if (originsList.includes(req.headers.origin as string)) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
} else {
res.header('Access-Control-Allow-Origin', defaultOrigin);
}
} else {
res.header('Access-Control-Allow-Origin', req.headers.origin);
}

if (method === 'OPTIONS') {
res.header('Access-Control-Max-Age', '300');
Expand Down Expand Up @@ -262,14 +274,14 @@ export async function executeWebhook(
);
const responseCode = workflow.expression.getSimpleParameterValue(
workflowStartNode,
webhookData.webhookDescription.responseCode,
webhookData.webhookDescription.responseCode as string,
executionMode,
additionalKeys,
undefined,
200,
) as number;

const responseData = workflow.expression.getSimpleParameterValue(
const responseData = workflow.expression.getComplexParameterValue(
workflowStartNode,
webhookData.webhookDescription.responseData,
executionMode,
Expand Down Expand Up @@ -324,7 +336,7 @@ export async function executeWebhook(
// TODO: pass a custom `fileWriteStreamHandler` to create binary data files directly
});
req.body = await new Promise((resolve) => {
form.parse(req, async (err, data, files) => {
form.parse(req, async (_err, data, files) => {
normalizeFormData(data);
normalizeFormData(files);
resolve({ data, files });
Expand Down Expand Up @@ -455,6 +467,12 @@ export async function executeWebhook(
responseCallback(null, {
responseCode,
});
} else if (responseData) {
// Return the data specified in the response data option
responseCallback(null, {
data: responseData as IDataObject,
responseCode,
});
} else if (webhookResultData.webhookResponse !== undefined) {
// Data to respond with is given
responseCallback(null, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class WebhookNotFoundError extends NotFoundError {

const hintMsg =
hint === 'default'
? "Click the 'Execute workflow' button on the canvas, then try again. (In test mode, the webhook only works for one call after you click this button)"
? "Click the 'Test workflow' button on the canvas, then try again. (In test mode, the webhook only works for one call after you click this button)"
: "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)";

super(errorMsg, hintMsg);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Service } from 'typedi';
import { CacheService } from '@/services/cache/cache.service';
import { type IWebhookData } from 'n8n-workflow';
import type { IWebhookData } from 'n8n-workflow';
import type { IWorkflowDb } from '@/Interfaces';
import { TEST_WEBHOOK_TIMEOUT, TEST_WEBHOOK_TIMEOUT_BUFFER } from '@/constants';

Expand Down
30 changes: 29 additions & 1 deletion packages/core/src/NodeExecuteFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import type {
NodeExecutionWithMetadata,
NodeHelperFunctions,
NodeParameterValueType,
NodeTypeAndVersion,
PaginationOptions,
RequestHelperFunctions,
Workflow,
Expand Down Expand Up @@ -2798,7 +2799,34 @@ const getCommonWorkflowFunctions = (
active: workflow.active,
}),
getWorkflowStaticData: (type) => workflow.getStaticData(type, node),

getChildNodes: (nodeName: string) => {
const output: NodeTypeAndVersion[] = [];
const nodes = workflow.getChildNodes(nodeName);

for (const nodeName of nodes) {
const node = workflow.nodes[nodeName];
output.push({
name: node.name,
type: node.type,
typeVersion: node.typeVersion,
});
}
return output;
},
getParentNodes: (nodeName: string) => {
const output: NodeTypeAndVersion[] = [];
const nodes = workflow.getParentNodes(nodeName);

for (const nodeName of nodes) {
const node = workflow.nodes[nodeName];
output.push({
name: node.name,
type: node.type,
typeVersion: node.typeVersion,
});
}
return output;
},
getRestApiUrl: () => additionalData.restApiUrl,
getInstanceBaseUrl: () => additionalData.instanceBaseUrl,
getInstanceId: () => Container.get(InstanceSettings).instanceId,
Expand Down
112 changes: 112 additions & 0 deletions packages/nodes-base/credentials/icons/jwt.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit e84c27c

Please sign in to comment.