|
|
@@ -0,0 +1,120 @@
|
|
|
+/**
|
|
|
+ * @node respond-to-webhook
|
|
|
+ * @name Respond to Webhook
|
|
|
+ * @category core
|
|
|
+ * @version 1.0.0
|
|
|
+ * @description Set the status, headers and body a webhook-triggered workflow returns to its caller
|
|
|
+ * @icon reply
|
|
|
+ */
|
|
|
+
|
|
|
+const configSchema = {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ status: {
|
|
|
+ type: 'number',
|
|
|
+ title: 'Status Code',
|
|
|
+ description: 'HTTP status to return, such as 200, 201, 400 or 404',
|
|
|
+ default: 200
|
|
|
+ },
|
|
|
+ bodySource: {
|
|
|
+ type: 'string',
|
|
|
+ title: 'Body From',
|
|
|
+ description: 'json sends the text below parsed as JSON, text sends it as it is, and input sends a value taken from the incoming data',
|
|
|
+ enum: ['json', 'text', 'input'],
|
|
|
+ default: 'json'
|
|
|
+ },
|
|
|
+ body: {
|
|
|
+ type: 'string',
|
|
|
+ title: 'Body',
|
|
|
+ description: 'The response body, for the json and text sources. Supports {{variable}} interpolation',
|
|
|
+ format: 'textarea'
|
|
|
+ },
|
|
|
+ bodyField: {
|
|
|
+ type: 'string',
|
|
|
+ title: 'Body Field',
|
|
|
+ description: 'Path to the value to send, for the input source, such as data.result',
|
|
|
+ default: 'data'
|
|
|
+ },
|
|
|
+ contentType: {
|
|
|
+ type: 'string',
|
|
|
+ title: 'Content Type',
|
|
|
+ description: 'Content-Type header. Leave empty to send application/json',
|
|
|
+ default: 'application/json'
|
|
|
+ },
|
|
|
+ headers: {
|
|
|
+ type: 'object',
|
|
|
+ title: 'Extra Headers',
|
|
|
+ description: 'Additional response headers',
|
|
|
+ additionalProperties: { type: 'string' }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const inputSchema = {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ data: { type: 'any' }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const outputSchema = {
|
|
|
+ type: 'object',
|
|
|
+ properties: {
|
|
|
+ status: { type: 'number', description: 'Status this node asked for' },
|
|
|
+ respondedWith: { type: 'string', description: 'Content type sent' }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+async function execute(config, input, context) {
|
|
|
+ const status = config.status === undefined || config.status === null || config.status === ''
|
|
|
+ ? 200
|
|
|
+ : Number(config.status);
|
|
|
+ if (isNaN(status) || status < 100 || status > 599) {
|
|
|
+ throw new Error('Respond to Webhook: "' + config.status +
|
|
|
+ '" is not an HTTP status code. Use a number from 100 to 599');
|
|
|
+ }
|
|
|
+
|
|
|
+ const source = config.bodySource || 'json';
|
|
|
+ const contentType = config.contentType || 'application/json';
|
|
|
+
|
|
|
+ let body;
|
|
|
+ if (source === 'input') {
|
|
|
+ body = smartbotic.utils.getFieldValue(input, config.bodyField || 'data');
|
|
|
+ } else if (source === 'text') {
|
|
|
+ body = config.body === undefined || config.body === null ? '' : String(config.body);
|
|
|
+ } else {
|
|
|
+ const raw = config.body === undefined || config.body === null ? '' : String(config.body);
|
|
|
+ if (raw.length === 0) {
|
|
|
+ body = {};
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ body = JSON.parse(raw);
|
|
|
+ } catch (e) {
|
|
|
+ throw new Error('Respond to Webhook: the body is not valid JSON: ' + e.message +
|
|
|
+ '. Use the text source to send it as it is');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const headers = {};
|
|
|
+ if (config.headers && typeof config.headers === 'object') {
|
|
|
+ for (const name of Object.keys(config.headers)) {
|
|
|
+ headers[name] = String(config.headers[name]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ headers['Content-Type'] = contentType;
|
|
|
+
|
|
|
+ smartbotic.log.info('Respond to Webhook: ' + status + ' as ' + contentType);
|
|
|
+
|
|
|
+ return {
|
|
|
+ status: status,
|
|
|
+ respondedWith: contentType,
|
|
|
+ _webhookResponse: {
|
|
|
+ status: status,
|
|
|
+ headers: headers,
|
|
|
+ body: body
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+module.exports = { configSchema, inputSchema, outputSchema, execute };
|