Skip to content

Instantly share code, notes, and snippets.

@composer2 composer2/README.md
Last active Dec 19, 2018

Embed
What would you like to do?
Axway Flow SDK

Creating flow-nodes for API Builder Standalone with Axway Flow SDK

API Builder is tool that enables developers to rapidly create APIs and microservices with a low-code/no-code approach. API Builder achieves this by enabling you to develop your business logic using Flows. A flow allows you to orchestrate your business logic visually as a graph of connected flow-nodes.

The Axway Flow SDK (axway-flow-sdk) is a standalone utility that enables the creation of custom flow-nodes for API Builder flows. By offering the Axway Flow SDK as a standalone utility, new flow-nodes can be developed and consumed in API Builder.

In this post we'll look at features available in the Axway Flow SDK and how easy is to create a new flow-node. For this example we'll create MD5 flow-node and integrate it in API Builder.

Instaling the Axway Flow SDK

npm install -g axway-flow-sdk

Use the Axway Flow SDK

The following generates a new flow-node starter project in the current directory. You can customize the starter project to meet your requirements.

axway-flow -n <node name>
cd <node name>
npm install
npm run build

The generated starter project name is prefixed with the required api-builder-plugin-fn- prefix.

The starter project is heavily commented to simplify the process of customizing it. It also comes with the eslint configuration and the mocha unit tests incorporated to help you ensure the quality of your custom flow-node.

Sample MD5 flow-node

As an example of how to write a flow-node, we will examine creating a flow-node that allows the hashing of strings from within the flow.

Create the project

axway-flow -n md5 -d 'MD5 hashing of strings.'
cd api-builder-plugin-fn-md5
npm install
npm install md5
npm run build

Customize the 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);

	// The unique name of your flow-node.  You can define multiple flow-nodes in this
	// file, but one is typical.
	flownodes.add('md5', {
		name: 'Md5',
		// file support for: svg, png, gif, bmp, jpg, and tiff
		icon: 'icon.svg',
		description: 'MD5 hashing of strings.'
	})
		// Add a method to your flow-node.
		.method('md5', {
			name: 'MD5',
			description: 'Perform a MD5 hash.'
		})
		// Add parameter(s) to your method.
		.parameter('plaintext', {
			description: 'The plain text to hash.',
			type: 'string'
		}, true)
		// Once all parameters for the method are defined, add output(s) to your method.
		.output('next', {
			name: 'Next',
			description: 'The hashed value',
			context: '$.hash',
			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. Describe the flow-node, name, description, category, and icon:
.add('md5', {
	name: 'Md5',
	// file support for: svg, png, gif, bmp, jpg, and tiff
	icon: 'icon.svg',
	description: 'MD5 hashing of strings.'
})

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. Below you can find an icon.svg which represent a hash, download it and use it. Hash icon for md5 flow-node

  1. Add a method to the flow-node and describe its parameters:
.method('md5', {
	name: 'MD5',
	description: 'Perform a MD5 hash.'
})

A method called md5, that is displayed in the Flow Editor as MD5, was added. The md5 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.

  1. Describe the flow-node parameters and the name to access them:
.parameter('plaintext', {
	description: 'The plain text to hash.',
	type: 'string'
}, true)

In this example, the parameter is defined as plaintext.

  1. Describe the possible outputs from the method:
.output('next', {
	name: 'Next',
	description: 'The hashed value',
	context: '$.hash',
	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.

  1. Define the implementation:
	.action(action);

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

Customize the flow-node method implementation

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

const md5 = require('md5');
exports = module.exports = function (req, cb) {
	const param = req.params.plaintext;
	if (!param) {
		// invoking the callback with an error will terminate the flow.
		return cb('invalid argument');
	}
	cb.next(null, md5(param));
};

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 (define in index.js file). In this example, the parameter for the hash method is defined as plaintext:

.parameter('plaintext', {
	description: 'The plain text to hash.',
	type: 'string'
}, true)

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

return cb('invalid argument');

Unit test your flow-node

The starter project includes automatically generated unit tests in the ./test directory of your project. The tests are for example purposes and will need to be customized to your specific use case. The SDK provides a mocknode that allows for mock invocations of your flow-node methods.

Use mocknode to test error callback existence - valid argument

This example uses mocha to check that the specification is defined well enough to pass the plaintext argument to the method. It also mocks the callback using the defined output of the specification and ensures that the method invokes the correct callback.

const md5 = require('md5');

it('[TEST-3] should succeed', () => {
const hashed = md5('some string');
    return mocknode(flownodes).node('md5')
        .invoke('md5', { plaintext: 'some string' })
        .then((data) => {
            expect(data).to.deep.equal({
                    next: [ null, hashed ]
            });
        });
});

Using mocknode to test error callback existence - invalid argument

This example is similar to the previous example, except that the method will invoke a cb('invalid argument') when given an undefined parameter.

it('[TEST-4] should fail to with invalid argument', () => {
    return mocknode(flownodes).node('md5')
        .invoke('md5', { plaintext: null })
        .then((data) => {
            expect(data).to.deep.equal(
            [ 'invalid argument' ]
        );
        });
});

Testing that validity of the flow-node specification

The Axway Flow SDK tries to prevent the creation of invalid flow-node specifications, but there are some edge cases where it may be possible to generate a flow-node specification that is invalid at runtime. To detect this, the generated specification should be validated as part of your unit tests.

it('[TEST-5] should define valid node specs', () => {
    expect(validate(flownodes)).to.not.throw;
});

Installing the flow-node in API Builder

While unit testing is important, it is also necessary to be able to install the custom flow-node into your local API Builder for testing.

Create installable flow-node

This can be achieved by packing the module locally:

cd api-builder-plugin-fn-md5
npm install
npm run build
npm pack

This will create a tgz archive (api-builder-plugin-fn-md5-1.0.0.tgz) that can then be installed into your API Builder.

Create API Builder service

npx @axway/api-builder init md5-demo
cd md5-demo
npm install --no-optional
npm install <path to flow node project>/api-builder-plugin-fn-md5-1.0.0.tgz
npm start

API Builder will now be running and accessible on http://localhost:8080/console.

Use the md5 flow-node

Navigate to Greeting API endpoint

Click on Flow link so you can go to the flow editor: On the picture below you can see the finish state of our flow.

The sidebar has our newly create md5 under General flow-node drag&drop it in the editor and place it between the Check Username node and Format Greeting

In MD5 node we have to make one change under parameters

Use this snippet:

$.params.username

In Format Greeting node we have to change the template so we can see our hashed string like so:

Use this snippet:

{{=it.config.helloworld.salutation}}
{{=it.hash}}

That's all we need to implement our new flow-node, we can now apply the changes and close the editor, which will navigate us to the Greeting API endpoint. In order to test it we have to expand the endpoint and enter random username and click execute. The outcome should be as follow

Summary

Creating with Axway Flow SDK is a simple, fast and easy process. You can create various different flow-nodes and properly unit test them before using them in API Builder endpoints. This gives you the flexibility to integrate with whichever endpoint you need to, without having to sacrifice the low-code/no-code experience API Builder provides.

Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@charles-jaynes

This comment has been minimized.

Copy link

charles-jaynes commented Dec 19, 2018

Please refer to my edits and updates at the following: https://gist.github.com/charles-jaynes/52b539d37b79c548a23935782f6071c3

Please note the changes I made.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.