Documentation

0.7.8 API docs

Graphs

NoFlo graph file format


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": "source"
      }
    },
    {
      "src": {
        "process": "Read File",
        "port": "out"
      },
      "tgt": {
        "process": "Split by Lines",
        "port": "in"
      }
    },
    ...
  ]
}

To run a graph file, you can either use the load command of the NoFlo shell, or do it programmatically:

noflo = require "noflo"
noflo.loadFile "example.json", (network) ->
  console.log "Graph loaded"
  console.log network.graph.toDOT()
var noflo = require("noflo");
noflo.loadFile("example.json", function(network) {
  console.log("Graph loaded");
  console.log(network.graph.toDOT());
});

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' -> SOURCE Read(ReadFile) OUT -> IN Split(SplitStr)
Split OUT -> IN Count(Counter) COUNT -> IN Display(Output)
Read ERROR -> IN Display

Loading and running graphs

NoFlo supports the FBP language fully. You can either load a graph with a string of FBP-language commands with:

fbpData = "<some FBP language connections>"

noflo = require "noflo"
noflo.graph.loadFbp fbpData, (graph) ->
  console.log "Graph loaded"
  console.log graph.toDOT()
var fbpData = "<some FBP language connections>";

var noflo = require("noflo");
noflo.graph.loadFbp(fbpData, function(graph) {
  console.log("Graph loaded");
  console.log(graph.toDOT());
 });

The .fbp file suffix is used for files containing FBP language. This means you can load them also the same way as you load JSON files, using the noflo.loadFile method, or the NoFlo shell. Example:

$ noflo examples/linecount/count.fbp

FBP to JSON

flowbased can be used to convert your FBP to JSON.

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
fbp = document.getElementById('main').textContent.trim()

# Load the NoFlo graph based on the FBP string
noflo.graph.loadFBP fbp, (graph) ->
  # Run the graph
  noflo.createNetwork graph
// Get the FBP contents
var fbp = document.getElementById('main').textContent.trim();

// Load the NoFlo graph based on the FBP string
noflo.graph.loadFBP(fbp, function (graph) {

  // Run the graph
  noflo.createNetwork(graph);
});

Subgraphs

A NoFlo graph may contain multiple subgraphs, managed by instances of the 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, and looks for unattached ports in it. It then exposes these ports as its own inports or outports. This way a graph containing subgraphs can easily connect data between the main graph and the subgraph.

Unattached ports from the subgraph will be available through naming ProcessName.port on the Graph component instance.

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

Count

# File: graphs/count.fbp
INPORT=Read.IN:FILENAME
OUTPORT=Count.COUNT:COUNT
OUTPORT=Read.ERROR:ERROR

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

Main

# File: graphs/main.fbp

# Read a file (using our subgraph defined above)
'package.json' -> IN Count(Count)
Count() COUNT -> IN Display(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' -> READ.SOURCE Reader()
# Display the results
Reader() ENTITIZE.OUT -> IN Display(Output)

Just like with components, it is possible to share subgraphs via NPM. You have to register them in your package.json, for example:

{
  "name": "noflo-spreadsheet",
  "noflo": {
    "graphs": {
      "Parse": "./graphs/parse.fbp"
    }
  }
}

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.