Get Description of nodes in a flow programatically

Hi,

I need to get the description of the nodes in a flow programmatically for further processing tasks. I can get this description content manually by selecting the required node set and then using Export ->Clipbord in menu buttons. I am designing a custom node which programmatically reads the description of all nodes in current flow and then stores it in a given place on the deployment event of the flow. I have included the drawing of a sample scenario for your information.

How can I read the description of the current flow? Is there any API which provides this information? (which provides the description in manually export).

Thank you.

I've done a proof of concept

You have to change the inject to match the name of your flow and change the 1st file node to the name of your flowsxxx.json file (and change the 2nd file node to filename you want to save it it to)

It basically scans the flowsxxx.json file looking for name of the flow - when it finds it - it saves it into flow.flowID and then 3 seconds later, it collects all the bits of the flowsxxx.json file that belong to that flow.flowID

[{"id":"52cc66a7.003278","type":"inject","z":"44b61ea7.e0f69","name":"","topic":"","payload":"Flow 14","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":120,"wires":[["f03cc5e0.de1578","fed764ff.b253a8"]]},{"id":"5042d81e.09eb78","type":"file in","z":"44b61ea7.e0f69","name":"","filename":"flows_win8.json","format":"utf8","chunk":false,"sendError":false,"x":520,"y":120,"wires":[["f78e8ec.6793f7"]]},{"id":"f03cc5e0.de1578","type":"change","z":"44b61ea7.e0f69","name":"","rules":[{"t":"set","p":"flowName","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":120,"wires":[["5042d81e.09eb78"]]},{"id":"d7fac159.078cc","type":"debug","z":"44b61ea7.e0f69","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1150,"y":160,"wires":[]},{"id":"73551d26.65b494","type":"split","z":"44b61ea7.e0f69","name":"","splt":"","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":830,"y":120,"wires":[["28974b2b.09e8a4","b015a0fe.ab264"]]},{"id":"f78e8ec.6793f7","type":"json","z":"44b61ea7.e0f69","name":"","property":"payload","action":"","pretty":false,"x":690,"y":120,"wires":[["73551d26.65b494"]]},{"id":"28974b2b.09e8a4","type":"switch","z":"44b61ea7.e0f69","name":"","property":"payload.label","propertyType":"msg","rules":[{"t":"eq","v":"flowName","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":990,"y":120,"wires":[["d7fac159.078cc","6bf47b3a.1e4864"]]},{"id":"6bf47b3a.1e4864","type":"change","z":"44b61ea7.e0f69","name":"","rules":[{"t":"set","p":"flowID","pt":"flow","to":"payload.id","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1160,"y":120,"wires":[[]]},{"id":"b015a0fe.ab264","type":"delay","z":"44b61ea7.e0f69","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":220,"y":220,"wires":[["4d8797b2.ab31f8"]]},{"id":"4d8797b2.ab31f8","type":"switch","z":"44b61ea7.e0f69","name":"","property":"payload.z","propertyType":"msg","rules":[{"t":"eq","v":"flowID","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":410,"y":220,"wires":[["40889b4f.f59414"]]},{"id":"40889b4f.f59414","type":"join","z":"44b61ea7.e0f69","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"CYCYCY","joinerType":"str","accumulate":false,"timeout":"5","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":610,"y":220,"wires":[["118b540b.a6f74c"]]},{"id":"4b4cfe58.dff8c","type":"file","z":"44b61ea7.e0f69","name":"","filename":"test.json","appendNewline":true,"createDir":false,"overwriteFile":"true","x":1000,"y":220,"wires":[[]]},{"id":"118b540b.a6f74c","type":"json","z":"44b61ea7.e0f69","name":"","property":"payload","action":"str","pretty":false,"x":750,"y":220,"wires":[["4b4cfe58.dff8c","d7fac159.078cc"]]},{"id":"7e99b906.d5f948","type":"inject","z":"44b61ea7.e0f69","name":"","topic":"","payload":"Hello World","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":40,"wires":[["73a4cddf.408034"]]},{"id":"73a4cddf.408034","type":"debug","z":"44b61ea7.e0f69","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":290,"y":40,"wires":[]},{"id":"fed764ff.b253a8","type":"change","z":"44b61ea7.e0f69","name":"","rules":[{"t":"set","p":"flowName","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":130,"y":160,"wires":[[]]}]

I created some "introspection" flows last year, so I could get a count of all the nodes in the current flow -- perhaps it is a starting point for what you are trying to do?

[{"id":"1af1379.13d21c8","type":"inject","z":"c9d31bae.be4a78","name":"get counts","topic":"counts/*","payload":"{}","payloadType":"json","repeat":"","crontab":"","once":false,"x":120,"y":120,"wires":[["db65453d.202d68"]]},{"id":"db65453d.202d68","type":"http request","z":"c9d31bae.be4a78","name":"GET /admin/flows","method":"GET","ret":"obj","url":"http://localhost:18806/admin/flows","tls":"","x":370,"y":80,"wires":[["f772177f.65d988","66cffc9b.2a1c24"]]},{"id":"66cffc9b.2a1c24","type":"change","z":"c9d31bae.be4a78","name":"Node counts","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload^($uppercase(type)) {\t    \"*\": $count($$.payload),\t    $substringBefore(type, \":\"): $count([$])\t}\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":120,"wires":[["73e3ba50.38de24","f772177f.65d988"]]},{"id":"f772177f.65d988","type":"debug","z":"c9d31bae.be4a78","name":"","active":true,"console":"false","complete":"false","x":770,"y":120,"wires":[]}]

Anyway, it is safer to use the admin "/flows" api to retrieve a JSON description of all the currently deployed nodes, rather than trying to read the flow file... then it's just a matter of reformatting the node information for storage.

I think you might have missed off some nodes when you copy/pasted them into your reply - this is all I seem to get

Right, those 4 nodes show the concept, so it's all I exported -- most people don't have swagger nodes installed, so I didn't want to muddy the water...

Simon,

I've exported the entire set of flows to the library, in case you are interested...
https://flows.nodered.org/flow/87705f8d39d18c6e48ed0a01e54b8e3b

2 Likes

Thanks to @shrickus , I've simplified the flow so that it doesn't need to scan the flows_xxx.json :slight_smile:

[{"id":"52cc66a7.003278","type":"inject","z":"44b61ea7.e0f69","name":"","topic":"","payload":"Flow 14","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":120,"wires":[["f03cc5e0.de1578","fed764ff.b253a8"]]},{"id":"f03cc5e0.de1578","type":"change","z":"44b61ea7.e0f69","name":"","rules":[{"t":"set","p":"flowName","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":120,"wires":[["94f085b4.7b33b8"]]},{"id":"d7fac159.078cc","type":"debug","z":"44b61ea7.e0f69","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1030,"y":160,"wires":[]},{"id":"73551d26.65b494","type":"split","z":"44b61ea7.e0f69","name":"","splt":"","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":710,"y":120,"wires":[["28974b2b.09e8a4","b015a0fe.ab264"]]},{"id":"28974b2b.09e8a4","type":"switch","z":"44b61ea7.e0f69","name":"","property":"payload.label","propertyType":"msg","rules":[{"t":"eq","v":"flowName","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":870,"y":120,"wires":[["d7fac159.078cc","6bf47b3a.1e4864"]]},{"id":"6bf47b3a.1e4864","type":"change","z":"44b61ea7.e0f69","name":"","rules":[{"t":"set","p":"flowID","pt":"flow","to":"payload.id","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1040,"y":120,"wires":[[]]},{"id":"b015a0fe.ab264","type":"delay","z":"44b61ea7.e0f69","name":"","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":220,"y":220,"wires":[["4d8797b2.ab31f8"]]},{"id":"4d8797b2.ab31f8","type":"switch","z":"44b61ea7.e0f69","name":"","property":"payload.z","propertyType":"msg","rules":[{"t":"eq","v":"flowID","vt":"flow"}],"checkall":"true","repair":false,"outputs":1,"x":410,"y":220,"wires":[["40889b4f.f59414"]]},{"id":"40889b4f.f59414","type":"join","z":"44b61ea7.e0f69","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"CYCYCY","joinerType":"str","accumulate":false,"timeout":"5","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":610,"y":220,"wires":[["118b540b.a6f74c"]]},{"id":"4b4cfe58.dff8c","type":"file","z":"44b61ea7.e0f69","name":"","filename":"test.json","appendNewline":true,"createDir":false,"overwriteFile":"true","x":960,"y":220,"wires":[[]]},{"id":"118b540b.a6f74c","type":"json","z":"44b61ea7.e0f69","name":"","property":"payload","action":"str","pretty":false,"x":750,"y":220,"wires":[["4b4cfe58.dff8c","d7fac159.078cc"]]},{"id":"7e99b906.d5f948","type":"inject","z":"44b61ea7.e0f69","name":"","topic":"","payload":"Hello World","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":40,"wires":[["73a4cddf.408034"]]},{"id":"73a4cddf.408034","type":"debug","z":"44b61ea7.e0f69","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":290,"y":40,"wires":[]},{"id":"fed764ff.b253a8","type":"change","z":"44b61ea7.e0f69","name":"","rules":[{"t":"set","p":"flowName","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":130,"y":160,"wires":[[]]},{"id":"94f085b4.7b33b8","type":"http request","z":"44b61ea7.e0f69","name":"GET /admin/flows","method":"GET","ret":"obj","url":"http://localhost:1880/flows","tls":"","x":530,"y":120,"wires":[["73551d26.65b494"]]}]

Yes, this API is the one I was looking for.

/flows API call gives the description of all deployed flows in the runtime. This is a challenge for me to get only the description of the current flow of a node. I am writing a node to get the description of the flow in which that node belongs to. (using /flows API call). I can get the response and select the flow from it, but I need some kind of identification for that. Can a node get it's id/ flow id or any other identifying information in its runtime?

I just realized that I can get node's id by the node using this.id and I think it is sufficient for me.

Is there any way to get the flow id which the node belongs to.?

I could get it by this.z

Perhaps try the /flow api? Not sure if it requires a flow id, or returns the current flow -- check the docs.

Sorry If I made any confusion. Yes I can get it by just /flow endpoint. No need to use any id. It returns the description of all flow. I can find the current flow of a node using this.z property and I can use that ID to pick only nodes and connections of the current flow. Thanks.