Documentation

1.4.3 API docs

Graphs

Graphs are the way a NoFlo program is defined. A graph has a set of nodes, each representing an instance of a component or another graph, and edges connecting their ports to each other.

Graph loading

By default, NoFlo discovers and loads graphs from the graphs/ folder of your project, as well as the graphs/ folders of any of your NPM dependencies.

Graphs placed in this folder get named based on the filename, so components/DoSomething.json becomes available as component DoSomething. To prevent name clashes, you can also use the fully-qualified name project-name/DoSomething, where project-name comes from the name given in package.json.

Read more about the project directory structure in Publishing modules.

JSON

In addition to using NoFlo in embedded mode where you create the FBP graph programmatically (see example), you can also initialize and run graphs defined using a JSON file.

The NoFlo JSON files declare the processes used in the FBP graph, and the connections between them. They look like the following:

{
  "properties": {
    "name": "Count lines in a file"
  },
  "processes": {
    "Read File": {
      "component": "ReadFile",
      "metadata": {
        ...
      }
    },
    "Split by Lines": {
      "component": "SplitStr"
    },
    ...
  },
  "connections": [
    {
      "data": "package.json",
      "tgt": {
        "process": "Read File",
        "port": "in"
      }
    },
    {
      "src": {
        "process": "Read File",
        "port": "out"
      },
      "tgt": {
        "process": "Split by Lines",
        "port": "in"
      }
    },
    ...
  ]
}

Please refer to the Graph JSON Schema for full definition.

FBP

In addition to the JSON format described above, FBP has its own Domain-Specific Language (DSL) for easy graph definition. The syntax is the following:

  • 'somedata' -> PORT Process(Component) sends initial data somedata to port PORT of process Process that runs component Component
  • A(Component1) X -> Y B(Component2) sets up a connection between port X of process A that runs component Component1 and port Y of process B that runs component Component2

You can connect multiple components and ports together on one line, and separate connection definitions with a newline or a comma (,).

You can find more information in the README of the stand-alone FBP parser.

Example:

'somefile.txt' -> IN Read(ReadFile) OUT -> IN Split(SplitStr)
Split OUT -> IN Count(Counter) COUNT -> IN Display(Output)
Read ERROR -> IN Display

Converting FBP to JSON

The FBP tool can be used to convert your FBP to JSON. Start by installing the command-line tool:

$ npm install -g fbp

Now you can convert a .fbp graph to JSON by running:

$ fbp path/to/graph.fbp

This will output the graph to standard out. Write it to a file with:

$ fbp path/to/graph.fbp > path/to/graph.json

Subgraphs

NoFlo graphs can also be used as components inside another graph. These subgraphs are provided by instances of the NoFlo built-in Graph component.

Subgraphs are useful for packaging particular flows to be used as a “new component” by other flows. This allows building more advanced functionality by creating reusable graphs of connected components.

The Graph component loads the graph given to it as a new NoFlo network. The graph’s exported in and outports become the ports of this new component instance.

A simple example, using a subgraph as a component by splitting linecount example fbp into two files:

Count

# File: graphs/count.fbp
# Define the ports exported from this subgraph
INPORT=Read.IN:FILENAME
OUTPORT=Count.COUNT:COUNT
OUTPORT=Read.ERROR:ERROR

# Split the file contents by newlines
Read(filesystem/ReadFile) OUT -> IN Split(strings/SplitStr)
# Count the packets
Split OUT -> IN Count(packets/Counter)

Main

# File: graphs/main.fbp

# Read a file (using our subgraph defined above)
'package.json' -> IN Count(Count)
Count COUNT -> IN Display(core/Output)

# Display also file read errors
Count ERROR -> IN Display

A more advanced example, specifying what file a spreadsheet-parsing subgraph should run with:

# Load a subgraph as a new process
'examples/spreadsheet/parse.fbp' -> GRAPH Reader(Graph)
# Send the filename to the component (subgraph)
'somefile.xls' -> FILENAME Reader
# Display the results
Reader COUNT -> IN Display(core/Output)

# Display also file read errors
Reader ERROR -> IN Display

Just like with components, it is possible to share subgraphs via NPM. Just make sure they’re contained in the graphs/ subdirectory of your package.

After this the subgraph is available as a “virtual component” with the name spreadsheet/Parse and can be used just like any other component. Subgraphs exported in this manner can be in either JSON or the .fbp format.

Read more about NPM modules in Publishing modules.

Executing graphs

To run a graph file, you can either use the noflo-nodejs tool:

$ noflo-nodejs example.json

Graphs can also be executed programmatically:

const noflo = require("noflo");
noflo.loadFile("example.json", (err, network) => {
  if (err) {
    throw err;
  }
  console.log("Graph loaded");
  console.log(network.graph.toDOT());
});

Inline FBP in web applications

In addition to separate files, FBP graph definitions can also be defined inline in HTML. The typical way to do this is to utilize a script tag. For example, the following would change the contents of an element identified with the ID header to say Hello World:

<script type="application/fbp" id="main">
  '#header' -> SELECTOR GetHeader(dom/GetElement)
  'Hello World' -> HTML WriteContent(dom/WriteHTML)
  GetHeader ELEMENT -> CONTAINER WriteContent
</script>

Loading and running inline FBP is quite simple:

// Get the FBP contents
const fbp = document.getElementById('main').textContent.trim();

// Load the NoFlo graph based on the FBP string
noflo.graph.loadFBP(fbp, (err, graph) => {
  if (err) {
    // Throw on parse errors
    throw err;
  }

  // Run the graph
  noflo.createNetwork(graph, (err, network) => {
    if (err) {
      // Throw if network can't be initialized
      throw err;
    }
    console.log('Network is running!');
  });
});

Read more about executing NoFlo graphs in JavaScript code in Embedding.