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 ComponentA(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.