Create a custom flow-node

This document describes how to create a custom flow-node.

Introduction

As an example of how to write a flow-node, we will examine creating and customizing a sample encodeURI flow-node that URI encodes a string. Creating and customizing the sample flow-node includes the following steps:

  1. Create the project
  2. Customize the flow-node definition
  3. Customize the flow-node method implementation

Prerequisites

Create the sample encodeURI flow-node

This tutorial will demonstrate how to create a custom flow-node for use in the API Builder Flow editor UI. For this example, we will create a flow node that will encode a URI given a string as an input using the encodeURI function.

Step 1: Create the project

Create and build the sample encodeURI flow-node.

Create a new flow-node plugin
axway-flow -n encodeuri -d "URI encoder."
cd api-builder-plugin-fn-encodeuri
npm install
npm run build

Step 2: Customize the flow-node definition

Customize the encodeURI flow-node definition in the index.js file.

const sdk = require('axway-flow-sdk');
const action = require('./action');
 
function getFlowNodes() {
	const flownodes = sdk.init(module);
	flownodes
		.add('encodeuri', {
			name: 'Encode URI',
			icon: 'icon.svg',
			description: 'URI encoder.',
			category: 'utils'
		})
		.method('encode', {
			name: 'Encode URI',
			description: 'Encodes a URI by replacing each instance of certain characters with UTF-8
						 encodings.'
		})
		.parameter('uri', {
			description: 'The URI to encode.',
			type: 'string'
		})
		.output('next', {
			name: 'Next',
			description: 'The URI was encoded successfully.',
			context: '$.encodedURI',
			schema: {
				type: 'string'
			}
		})
		.action(action);
	return Promise.resolve(flownodes);
}
 
exports = module.exports = getFlowNodes;

To explain what occurs in the index.js file, we will break the file down piece by piece.

  1. index.js is exporting a function that returns a promise that will resolve with the flow-node specifications. This approach allows for the asynchronous creation of the flow-node specifications which can be used, for example, to load resources from the network or perform asynchronous parsing.

  2. In the sample flow-node plugin, the actual specification is defined in getFlowNodes().
  3. Describe the flow-node, name, description, category, and icon:

    .add('encodeuri', {
            name: 'Encode URI',
            icon: 'icon.svg',
            description: 'URI encoder.',
            category: 'utils'
    })

    The name is the text that is displayed in the Flow Editor. The default icon is a placeholder (a star) that should be replaced with a graphic that represents the action of the flow-node. The icon is displayed at 28 pixels x 28 pixels. The category is the section in the Flow Editor tool panel where the flow-node is contained.

  4. Add a method to the flow-node and describe its parameters:

    .method('encode', {
            name: 'Encode URI',
            description: 'Encodes a URI by replacing each instance of certain characters with UTF-8 encodings.'
        })
        .parameter('uri', {
            description: 'The URI to encode.',
            type: 'string'
    })

    A method called encode, that is displayed in the Flow Editor as Encode URI, was added. The encode method has a single parameter. If there was more than one parameter, we would repeat the .parameter(name, schema) block. The second value in the parameter method is a JSON Schema that describes the parameter type.

  5. Describe the possible outputs from the method:

    .output('next', {
        name: 'Next',
        description: 'The URI was encoded successfully.',
        context: '$.encodedURI',
        schema: {
            type: 'string'
        }
    })

    The outputs section defines the possible outcomes of the flow-node. In this simple case there is just one output; however, flow-nodes can have multiple outputs with different return types. For example, this flow-node could have added an error output to indicate that encoding failed.

  6. Define the implementation:

    .action(action);

    The action() expects a function that will be passed the request details parameter and a callback object parameter.

Step 3: Customize the flow-node method implementation

To simplify management of the code, the starter project puts the implementation of the methods in the action.js file. There is not a requirement to follow this pattern, you can structure your project how best suits your needs.

exports = module.exports = function (req, cb) {
        const uri = req.params.uri;
        if (!uri) {
                return cb('invalid argument');
        }
        cb.next(null, encodeURI(uri));
};

This is a simple scenario, but it highlights the main features. The parameters for the flow-node method are accessed under the req.params parameter. In this example, the parameter for the encode method is defined as uri:

    .parameter('uri', {
        description: 'The URI to encode.',
        type: 'string'
    })

The logic checks that the parameter is set. If uri is not set, it fires a generic error callback.

return cb('invalid argument');

These errors are not handled and will abort the flow execution. In general, avoid doing this for any expected error scenarios. If there are known error situations, it is better to define an output for those scenarios and allow the flow designer the flexibility to specify what to do when an error occurs.

If uri is set, the fallback for the next output is fired. The name of this callback will match the name of the output defined in the method. For example, if you defined an output encoderError, then there would be a callback cb.encoderError(). The encoded string is passed to the callback as the methods output value.

Related Links