mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(Respond to Webhook Node): Continue on fail and error branch support (#9115)
This commit is contained in:
parent
064e8f4a1d
commit
86a20f6563
|
@ -11,7 +11,7 @@ import type {
|
||||||
import { jsonParse, BINARY_ENCODING, NodeOperationError } from 'n8n-workflow';
|
import { jsonParse, BINARY_ENCODING, NodeOperationError } from 'n8n-workflow';
|
||||||
import set from 'lodash/set';
|
import set from 'lodash/set';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { formatPrivateKey } from '../../utils/utilities';
|
import { formatPrivateKey, generatePairedItemData } from '../../utils/utilities';
|
||||||
|
|
||||||
export class RespondToWebhook implements INodeType {
|
export class RespondToWebhook implements INodeType {
|
||||||
description: INodeTypeDescription = {
|
description: INodeTypeDescription = {
|
||||||
|
@ -287,142 +287,158 @@ export class RespondToWebhook implements INodeType {
|
||||||
};
|
};
|
||||||
|
|
||||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||||
|
const items = this.getInputData();
|
||||||
const nodeVersion = this.getNode().typeVersion;
|
const nodeVersion = this.getNode().typeVersion;
|
||||||
|
|
||||||
if (nodeVersion >= 1.1) {
|
try {
|
||||||
const connectedNodes = this.getParentNodes(this.getNode().name);
|
if (nodeVersion >= 1.1) {
|
||||||
if (!connectedNodes.some((node) => node.type === 'n8n-nodes-base.webhook')) {
|
const connectedNodes = this.getParentNodes(this.getNode().name);
|
||||||
throw new NodeOperationError(
|
if (!connectedNodes.some((node) => node.type === 'n8n-nodes-base.webhook')) {
|
||||||
this.getNode(),
|
throw new NodeOperationError(
|
||||||
new Error('No Webhook node found in the workflow'),
|
this.getNode(),
|
||||||
{
|
new Error('No Webhook node found in the workflow'),
|
||||||
description:
|
{
|
||||||
'Insert a Webhook node to your workflow and set the “Respond” parameter to “Using Respond to Webhook Node” ',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const items = this.getInputData();
|
|
||||||
|
|
||||||
const respondWith = this.getNodeParameter('respondWith', 0) as string;
|
|
||||||
const options = this.getNodeParameter('options', 0, {});
|
|
||||||
|
|
||||||
const headers = {} as IDataObject;
|
|
||||||
if (options.responseHeaders) {
|
|
||||||
for (const header of (options.responseHeaders as IDataObject).entries as IDataObject[]) {
|
|
||||||
if (typeof header.name !== 'string') {
|
|
||||||
header.name = header.name?.toString();
|
|
||||||
}
|
|
||||||
headers[header.name?.toLowerCase() as string] = header.value?.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let statusCode = (options.responseCode as number) || 200;
|
|
||||||
let responseBody: IN8nHttpResponse | Readable;
|
|
||||||
if (respondWith === 'json') {
|
|
||||||
const responseBodyParameter = this.getNodeParameter('responseBody', 0) as string;
|
|
||||||
if (responseBodyParameter) {
|
|
||||||
if (typeof responseBodyParameter === 'object') {
|
|
||||||
responseBody = responseBodyParameter;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
responseBody = jsonParse(responseBodyParameter);
|
|
||||||
} catch (error) {
|
|
||||||
throw new NodeOperationError(this.getNode(), error as Error, {
|
|
||||||
message: "Invalid JSON in 'Response Body' field",
|
|
||||||
description:
|
description:
|
||||||
"Check that the syntax of the JSON in the 'Response Body' parameter is valid",
|
'Insert a Webhook node to your workflow and set the “Respond” parameter to “Using Respond to Webhook Node” ',
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const respondWith = this.getNodeParameter('respondWith', 0) as string;
|
||||||
|
const options = this.getNodeParameter('options', 0, {});
|
||||||
|
|
||||||
|
const headers = {} as IDataObject;
|
||||||
|
if (options.responseHeaders) {
|
||||||
|
for (const header of (options.responseHeaders as IDataObject).entries as IDataObject[]) {
|
||||||
|
if (typeof header.name !== 'string') {
|
||||||
|
header.name = header.name?.toString();
|
||||||
|
}
|
||||||
|
headers[header.name?.toLowerCase() as string] = header.value?.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusCode = (options.responseCode as number) || 200;
|
||||||
|
let responseBody: IN8nHttpResponse | Readable;
|
||||||
|
if (respondWith === 'json') {
|
||||||
|
const responseBodyParameter = this.getNodeParameter('responseBody', 0) as string;
|
||||||
|
if (responseBodyParameter) {
|
||||||
|
if (typeof responseBodyParameter === 'object') {
|
||||||
|
responseBody = responseBodyParameter;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
responseBody = jsonParse(responseBodyParameter);
|
||||||
|
} catch (error) {
|
||||||
|
throw new NodeOperationError(this.getNode(), error as Error, {
|
||||||
|
message: "Invalid JSON in 'Response Body' field",
|
||||||
|
description:
|
||||||
|
"Check that the syntax of the JSON in the 'Response Body' parameter is valid",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (respondWith === 'jwt') {
|
||||||
} else if (respondWith === 'jwt') {
|
try {
|
||||||
try {
|
const { keyType, secret, algorithm, privateKey } = (await this.getCredentials(
|
||||||
const { keyType, secret, algorithm, privateKey } = (await this.getCredentials(
|
'jwtAuth',
|
||||||
'jwtAuth',
|
)) as {
|
||||||
)) as {
|
keyType: 'passphrase' | 'pemKey';
|
||||||
keyType: 'passphrase' | 'pemKey';
|
privateKey: string;
|
||||||
privateKey: string;
|
secret: string;
|
||||||
secret: string;
|
algorithm: jwt.Algorithm;
|
||||||
algorithm: jwt.Algorithm;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let secretOrPrivateKey;
|
let secretOrPrivateKey;
|
||||||
|
|
||||||
if (keyType === 'passphrase') {
|
if (keyType === 'passphrase') {
|
||||||
secretOrPrivateKey = secret;
|
secretOrPrivateKey = secret;
|
||||||
} else {
|
} else {
|
||||||
secretOrPrivateKey = formatPrivateKey(privateKey);
|
secretOrPrivateKey = formatPrivateKey(privateKey);
|
||||||
|
}
|
||||||
|
const payload = this.getNodeParameter('payload', 0, {}) as IDataObject;
|
||||||
|
const token = jwt.sign(payload, secretOrPrivateKey, { algorithm });
|
||||||
|
responseBody = { token };
|
||||||
|
} catch (error) {
|
||||||
|
throw new NodeOperationError(this.getNode(), error as Error, {
|
||||||
|
message: 'Error signing JWT token',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const payload = this.getNodeParameter('payload', 0, {}) as IDataObject;
|
} else if (respondWith === 'allIncomingItems') {
|
||||||
const token = jwt.sign(payload, secretOrPrivateKey, { algorithm });
|
const respondItems = items.map((item) => item.json);
|
||||||
responseBody = { token };
|
responseBody = options.responseKey
|
||||||
} catch (error) {
|
? set({}, options.responseKey as string, respondItems)
|
||||||
throw new NodeOperationError(this.getNode(), error as Error, {
|
: respondItems;
|
||||||
message: 'Error signing JWT token',
|
} else if (respondWith === 'firstIncomingItem') {
|
||||||
});
|
responseBody = options.responseKey
|
||||||
}
|
? set({}, options.responseKey as string, items[0].json)
|
||||||
} else if (respondWith === 'allIncomingItems') {
|
: items[0].json;
|
||||||
const respondItems = items.map((item) => item.json);
|
} else if (respondWith === 'text') {
|
||||||
responseBody = options.responseKey
|
responseBody = this.getNodeParameter('responseBody', 0) as string;
|
||||||
? set({}, options.responseKey as string, respondItems)
|
} else if (respondWith === 'binary') {
|
||||||
: respondItems;
|
const item = items[0];
|
||||||
} else if (respondWith === 'firstIncomingItem') {
|
|
||||||
responseBody = options.responseKey
|
|
||||||
? set({}, options.responseKey as string, items[0].json)
|
|
||||||
: items[0].json;
|
|
||||||
} else if (respondWith === 'text') {
|
|
||||||
responseBody = this.getNodeParameter('responseBody', 0) as string;
|
|
||||||
} else if (respondWith === 'binary') {
|
|
||||||
const item = items[0];
|
|
||||||
|
|
||||||
if (item.binary === undefined) {
|
if (item.binary === undefined) {
|
||||||
throw new NodeOperationError(this.getNode(), 'No binary data exists on the first item!');
|
|
||||||
}
|
|
||||||
|
|
||||||
let responseBinaryPropertyName: string;
|
|
||||||
|
|
||||||
const responseDataSource = this.getNodeParameter('responseDataSource', 0) as string;
|
|
||||||
|
|
||||||
if (responseDataSource === 'set') {
|
|
||||||
responseBinaryPropertyName = this.getNodeParameter('inputFieldName', 0) as string;
|
|
||||||
} else {
|
|
||||||
const binaryKeys = Object.keys(item.binary);
|
|
||||||
if (binaryKeys.length === 0) {
|
|
||||||
throw new NodeOperationError(this.getNode(), 'No binary data exists on the first item!');
|
throw new NodeOperationError(this.getNode(), 'No binary data exists on the first item!');
|
||||||
}
|
}
|
||||||
responseBinaryPropertyName = binaryKeys[0];
|
|
||||||
|
let responseBinaryPropertyName: string;
|
||||||
|
|
||||||
|
const responseDataSource = this.getNodeParameter('responseDataSource', 0) as string;
|
||||||
|
|
||||||
|
if (responseDataSource === 'set') {
|
||||||
|
responseBinaryPropertyName = this.getNodeParameter('inputFieldName', 0) as string;
|
||||||
|
} else {
|
||||||
|
const binaryKeys = Object.keys(item.binary);
|
||||||
|
if (binaryKeys.length === 0) {
|
||||||
|
throw new NodeOperationError(
|
||||||
|
this.getNode(),
|
||||||
|
'No binary data exists on the first item!',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
responseBinaryPropertyName = binaryKeys[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const binaryData = this.helpers.assertBinaryData(0, responseBinaryPropertyName);
|
||||||
|
if (binaryData.id) {
|
||||||
|
responseBody = { binaryData };
|
||||||
|
} else {
|
||||||
|
responseBody = Buffer.from(binaryData.data, BINARY_ENCODING);
|
||||||
|
headers['content-length'] = (responseBody as Buffer).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!headers['content-type']) {
|
||||||
|
headers['content-type'] = binaryData.mimeType;
|
||||||
|
}
|
||||||
|
} else if (respondWith === 'redirect') {
|
||||||
|
headers.location = this.getNodeParameter('redirectURL', 0) as string;
|
||||||
|
statusCode = (options.responseCode as number) ?? 307;
|
||||||
|
} else if (respondWith !== 'noData') {
|
||||||
|
throw new NodeOperationError(
|
||||||
|
this.getNode(),
|
||||||
|
`The Response Data option "${respondWith}" is not supported!`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const binaryData = this.helpers.assertBinaryData(0, responseBinaryPropertyName);
|
const response: IN8nHttpFullResponse = {
|
||||||
if (binaryData.id) {
|
body: responseBody,
|
||||||
responseBody = { binaryData };
|
headers,
|
||||||
} else {
|
statusCode,
|
||||||
responseBody = Buffer.from(binaryData.data, BINARY_ENCODING);
|
};
|
||||||
headers['content-length'] = (responseBody as Buffer).length;
|
|
||||||
|
this.sendResponse(response);
|
||||||
|
} catch (error) {
|
||||||
|
if (this.continueOnFail()) {
|
||||||
|
const itemData = generatePairedItemData(items.length);
|
||||||
|
const returnData = this.helpers.constructExecutionMetaData(
|
||||||
|
[{ json: { error: error.message } }],
|
||||||
|
{ itemData },
|
||||||
|
);
|
||||||
|
return [returnData];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!headers['content-type']) {
|
throw error;
|
||||||
headers['content-type'] = binaryData.mimeType;
|
|
||||||
}
|
|
||||||
} else if (respondWith === 'redirect') {
|
|
||||||
headers.location = this.getNodeParameter('redirectURL', 0) as string;
|
|
||||||
statusCode = (options.responseCode as number) ?? 307;
|
|
||||||
} else if (respondWith !== 'noData') {
|
|
||||||
throw new NodeOperationError(
|
|
||||||
this.getNode(),
|
|
||||||
`The Response Data option "${respondWith}" is not supported!`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const response: IN8nHttpFullResponse = {
|
|
||||||
body: responseBody,
|
|
||||||
headers,
|
|
||||||
statusCode,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.sendResponse(response);
|
|
||||||
|
|
||||||
return [items];
|
return [items];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue