Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The following command installs the Axway Flow SDK.

Code Block
languagebash
npm install -g 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.

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

...

Create the project

Code Block
languagebash
axway-flow -n encodeuri -d “URI encoder.”
cd nodehandler-encodeuri
npm install
npm run build

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

Code Block
languagejs
collapsetrue
const sdk = require('axway-flow-sdk');
const action = require('./action');

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);
exports = module.exports = flownodes;

...

  1. Describe the flow-node, name, description, category, and icon:

    Code Block
    languagejs
    .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.

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

    Code Block
    languagejs
    .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.

  3. Describe the possible outputs from the method:

    Code Block
    languagejs
    .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.

  4. Define the implementation:

    Code Block
    languagejs
    .action(action);

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

...

To simplify the 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.

Code Block
languagejs
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:

Code Block
languagejs
    .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.

Code Block
languagejs
return cb('invalid argument');

...

This example uses mocha to check that the specification is defined well enough to pass the uri 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.

Code Block
languagejs
    it('[TEST-2] should succeed', () => {
        return mocknode(specs).node('encodeuri')
            .invoke('encode', { uri: 'some string' })
            .then((data) => {
                expect(data).to.deep.equal({
                        next: [ null, 'some%20string' ]
                });
            });
    });

...

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

Code Block
languagejs
    it('[TEST-3] should fail to with invalid argument', () => {
        return mocknode(specs).node('encodeuri')
            .invoke('encode', { uri: null })
            .then((data) => {
                expect(data).to.deep.equal(
                [ 'invalid argument' ]
            );
            });
    });

...

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.

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

...

While unit testing is important, it is also necessary to be able to install the custom flow-node into your local API Builder application for testing. This can be achieved by packing the module locally:

Code Block
languagebash
cd nodehandler-encodeuri
npm install
npm run build
npm pack

This will create a tgz archive (nodehandler-encodeuri-1.0.0.tgz) that can then be installed into your Arrow application.

Code Block
languagebash
cd <app-folder>
npm install <path to flow node project>/nodehandler-encodeuri-1.0.0.tgz
appc run

...

In Axway API Builder, it is possible to reference other types. For example, types can be loaded from ./schemas, registered from models, or registered from service connectors. Any registered schema can be referenced whenever a schema is required.

Code Block
languagejs
.parameter('greeting', {
    "$ref": "schema://model/appc.arrowdb/user"
})
.output('next', {
    schema: {
        "$ref": "schema://model/appc.arrowdb/user"
    }
})

...

ParameterTypeDefaultDescription
key

string

 A unique key identifier for the flow-node.
[options]

object

 Options for the flow-node.
[options.name]

string

 A friendly name for the flow-node as it will appear in the UI.
[options.icon]

string

 An icon file.
[options.description]

string

 A description for the flow-node.
[options.category]

string

general

A category under which the flow-node will appear in the UI.

Example:

Code Block
languagejs
sdk.init(module).add('encodeURI', { icon: 'encode.svg' });

...

ParameterTypeDescription
key

string

A unique key identifier for the method.
[options]

object

Options for the method.
[options.name]

string

A friendly name for the method as it will appear in the UI.

Example:

Code Block
languagejs
sdk.init(module).add('encodeURI', { icon: 'encode.svg' })
    .method('encode', { name: 'Encode URI' });

...

ParameterTypeDefaultDescription
name

string

 A unique name for the parameter as it will appear in the UI.
schema

object

 A schema used to validate the parameter.
[required]

boolean

true

A flag to indicate the parameter is required or optional.

Example:

Code Block
languagejs
sdk.init(module).add('encodeURI', { icon: 'encode.svg' })
    .method('encode', { name: 'Encode URI' })
    .parameter('uri', { type: 'string' });

...

ParameterTypeDescription
key

string

A unique key for the output.
[options.name]

string

A friendly name for the output as it will appear in the UI.
[options.description]

string

The output description.
[options.context]

string

The default context string.
[options.schema]

object

The expected JSON schema for the output value.

Example:

Code Block
languagejs
sdk.init(module).add('encodeURI', { icon: 'encode.svg' })
    .method('encode', { name: 'Encode URI' })
    .parameter('uri', { type: 'string' })
    .output('encoded', { context: '$.encodedURI', schema: { type: 'string' } });

...

ParameterTypeDescription
handler

handler

The action handler function.

Example:

Code Block
languagejs
sdk.init(module).add('encodeURI', { icon: 'encode.svg' })
    .method('encode', { name: 'Encode URI' })
    .parameter('uri', { type: 'string' })
    .output('encoded', { context: '$.encodedURI', schema: { type: 'string' } })
    .action((req, cb) => cb.encoded(null, encodeURI(req.params.uri));

...

ParameterTypeDescription
module

object

The flow-node module.

Example:

Code Block
languagejs
const sdk = require('axway-node-sdk');
exports = module.exports = sdk.init(module);

...

ParameterTypeDescription
req

request

The Request object.
cb

callback

The output callback.

Example:

Code Block
languagejs
cb.encoded(null, uncodeURI(req.params.uri));

Example:

Code Block
languagejs
cb('error!');

Anchor
flow
flow
axway-flow-sdk~flowCallback: function

...