# NodeRedForge
NodeRedForge is a Python-based tool designed to facilitate the generation of custom JSON API nodes for Node-RED.
![NodeRedForge Screenshot](/doc/images/example.png)
<!-- ![NodeRedForge Screenshot 2](/doc/images/example2.png) -->
## Installation
To install NodeRedForge, use the following pip command:
```bash
pip install nodered-forge
```
## Usage
### NodeForgeApp
To create custom API nodes for Node-RED, start by defining the application name and the base URL:
```python
from nodered_forge import NodeForgeApp
nodeforge_app = NodeForgeApp("TestTodoApi", "http://test_api:5000")
```
Additional options for initializing `NodeForgeApp` include:
```python
NodeForgeApp(name, base_url,
ignore_ssl_errors=False,
authentication=False, # Whether authentication is required for API requests.
authentication_header='Authorization', # Header used for authentication
package_name=None, # package name for generated Node-RED module
default_icon=None,
default_color=None, # HTML Color, a default color is generated randomly
default_category=None,
global_parameters_config=None # Global configuration for parameters shared across all API nodes
):
```
### Creating API nodes
API nodes can be created using either the method `nodeforge_app.register_api_node()` or the decorator `@nodeforge_app.api_node()`.
Example:
```python
@nodeforge_app.api_node('/todos/<str:todo_id>', method='GET')
@flask_app.route('/todos/<int:todo_id>', methods=['GET'])
def get_todo(todo_id):
todo = next((item for item in todos if item['id'] == todo_id), None)
if todo:
return jsonify({'todo': todo})
else:
return jsonify({'message': 'Todo not found'}), 404
```
Other options for adding API nodes include:
```python
nodeforge_app.register_api_node(
name, # for api_node decorator the name can be taken from the function name
route,
method='GET',
color=None, # HTML color code
category=None, # Category in Node-red pallet
icon=None,
parameters_config=None, # Configuration for API parameters
description='No API description is provided'
):
```
### API Parameters
API parameters can be set in three ways:
1. Using the `route` argument of either the method `nodeforge_app.register_api_node()` or the decorator `@nodeforge_app.api_node()`.
2. Using the `parameters_config` argument of either the method `nodeforge_app.register_api_node()` or the decorator `@nodeforge_app.api_node()`. This parameter accepts a list of parameter strings, dictionaries, or instances of `NodeParameter`.
3. Using the `global_parameters` argument in the initialization of `NodeForgeApp`. This argument accepts the same formats as `parameters_config`.
#### Parameter Strings
Parameter strings accept the following formats:
- `param_name`
- `param_type:param_name`
- `param_type:param_name:default_value`
### NodeParameter
There are three types of API parameters:
- Route parameters (constructing the URI stem),
- URL parameters (sent as URL-encoded key-values),
- Body parameters (sent as JSON).
Initialization options for `NodeParameter`:
```python
NodeParameter(
name,
type=InputType.STR,
default=None, # Default value
required=False
plain_type="text" # For plain input type, specifies the HTML input type.
route_param=False
url_param=False
options=None # List of options for parameters with a predefined set of values,
# Accepts an iterator either strings, value & label tuples,or dictionaries with value and label keys
multiple_select=False # Allows selecting multiple values if options are defined
):
```
### InputType
Input types accepted by `NodeParameter`:
- InputType.PLAIN
- InputType.STR
- InputType.NUM
- InputType.BOOL
- InputType.JSON
- InputType.DATE
- InputType.SELECT
All these types correspond to Node-RED [TypedInput Widget](https://nodered.org/docs/api/ui/typedInput/#options-types) types,
except for `InputType.PLAIN`, which uses a plain HTML input (you can set the type of the input using the `plain_type` argument).
Example:
```python
@nodeforge_app.api_node('/todos/<int:todo_id>', method='PUT', parameters_config=[
'str:text',
'date:due-date',
'bool:done',
NodeParameter('notes', type=InputType.PLAIN, plain_type='textarea'),
'int:level',
NodeParameter('tags', options=['work', 'personal', 'chore', 'family'], multiple_select=True),
NodeParameter('assigned-to', options=['me', 'you', 'him', 'her']),
NodeParameter(name="pretty", type=InputType.BOOL, default=True, url_param=True),
])
@flask_app.route('/todos/<int:todo_id>', methods=['PUT'])
@require_authentication
def update_todo(todo_id):
todo = next((item for item in todos if item['id'] == todo_id), None)
if todo:
data = request.get_json()
todo.update({
'text': data.get('text', todo['text']),
'done': data.get('done', todo['done']),
'due-date': data.get('due-date', todo['due-date']),
'tags': data.get('tags', todo['tags']),
'notes': data.get('notes', todo['notes']),
'level': data.get('level', todo['level']),
'assigned-to': data.get('assigned-to', todo['assigned-to'])
})
return jsonify({'todo': todo})
else:
return jsonify({'message': 'Todo not found'}), 404
```
This code will generate a custom node with the following edit view:
![Edit view screenshot for the previous example](/doc/images/example2.png)
## JSON Body Request
If a body parameter (neither `route_param` nor `url_param` is set to True) is included in the node config, a JSON body property is added to the custom node.
If this field is filled, body parameters from the form will be ignored, giving the user a way to send custom objects.
![JSON Body Request Screenshot](/doc/images/json_body.png)
### Generating Custom Nodes
After configuring the nodes, you can generate them using the `output_package` method:
```python
nodeforge_app.output_package('/modules')
```
This will create a package directory under `/modules` with the prefix "node-red-contrib-nodered-forge-" unless the `package_name` is specified in the initialization of `NodeForgeApp`.
To install the generated module in Node-RED, run the following commands:
```bash
cd /path/to/node-red/data/
npm install /modules/package-name
```
Restart Node-RED if the module is installed or updated.
## Test App
An example app can be found under `dev/test-api-docker/test_api_app.py`, which is a dummy todo manager with CRUD operations. There is also a Docker Compose file with both this app and Node-RED to test the app; don't forget to restart upon making changes to the test app.
Raw data
{
"_id": null,
"home_page": "https://github.com/xaled/nodered-forge",
"name": "nodered-forge",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3",
"maintainer_email": "",
"keywords": "library node-red code-generator",
"author": "Khalid Grandi",
"author_email": "kh.grandi@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/15/98/db6f5840fecd64a51b62e3a83386c2846663afb9ad91dabedad1ca3914a7/nodered-forge-1.0.0.tar.gz",
"platform": null,
"description": "# NodeRedForge\nNodeRedForge is a Python-based tool designed to facilitate the generation of custom JSON API nodes for Node-RED.\n\n![NodeRedForge Screenshot](/doc/images/example.png)\n<!-- ![NodeRedForge Screenshot 2](/doc/images/example2.png) -->\n\n## Installation\nTo install NodeRedForge, use the following pip command:\n\n```bash\npip install nodered-forge\n```\n\n## Usage\n### NodeForgeApp\nTo create custom API nodes for Node-RED, start by defining the application name and the base URL:\n\n```python\nfrom nodered_forge import NodeForgeApp\n\nnodeforge_app = NodeForgeApp(\"TestTodoApi\", \"http://test_api:5000\")\n```\n\nAdditional options for initializing `NodeForgeApp` include:\n\n```python\nNodeForgeApp(name, base_url,\n ignore_ssl_errors=False,\n authentication=False, # Whether authentication is required for API requests.\n authentication_header='Authorization', # Header used for authentication\n package_name=None, # package name for generated Node-RED module\n default_icon=None,\n default_color=None, # HTML Color, a default color is generated randomly\n default_category=None,\n global_parameters_config=None # Global configuration for parameters shared across all API nodes\n ):\n```\n\n### Creating API nodes\nAPI nodes can be created using either the method `nodeforge_app.register_api_node()` or the decorator `@nodeforge_app.api_node()`.\n\nExample:\n\n```python\n@nodeforge_app.api_node('/todos/<str:todo_id>', method='GET')\n@flask_app.route('/todos/<int:todo_id>', methods=['GET'])\ndef get_todo(todo_id):\n todo = next((item for item in todos if item['id'] == todo_id), None)\n if todo:\n return jsonify({'todo': todo})\n else:\n return jsonify({'message': 'Todo not found'}), 404\n```\n\nOther options for adding API nodes include:\n```python\nnodeforge_app.register_api_node(\n name, # for api_node decorator the name can be taken from the function name\n route,\n method='GET',\n color=None, # HTML color code\n category=None, # Category in Node-red pallet\n icon=None,\n parameters_config=None, # Configuration for API parameters\n description='No API description is provided'\n ):\n```\n\n### API Parameters\nAPI parameters can be set in three ways:\n\n1. Using the `route` argument of either the method `nodeforge_app.register_api_node()` or the decorator `@nodeforge_app.api_node()`.\n2. Using the `parameters_config` argument of either the method `nodeforge_app.register_api_node()` or the decorator `@nodeforge_app.api_node()`. This parameter accepts a list of parameter strings, dictionaries, or instances of `NodeParameter`.\n3. Using the `global_parameters` argument in the initialization of `NodeForgeApp`. This argument accepts the same formats as `parameters_config`.\n\n#### Parameter Strings\n\nParameter strings accept the following formats:\n\n- `param_name`\n- `param_type:param_name`\n- `param_type:param_name:default_value`\n\n### NodeParameter\n\nThere are three types of API parameters:\n- Route parameters (constructing the URI stem),\n- URL parameters (sent as URL-encoded key-values),\n- Body parameters (sent as JSON).\n\nInitialization options for `NodeParameter`:\n```python\nNodeParameter(\n name,\n type=InputType.STR,\n default=None, # Default value\n required=False\n plain_type=\"text\" # For plain input type, specifies the HTML input type.\n route_param=False\n url_param=False\n options=None # List of options for parameters with a predefined set of values,\n # Accepts an iterator either strings, value & label tuples,or dictionaries with value and label keys\n multiple_select=False # Allows selecting multiple values if options are defined\n ):\n```\n\n### InputType\n\nInput types accepted by `NodeParameter`:\n\n- InputType.PLAIN\n- InputType.STR\n- InputType.NUM\n- InputType.BOOL\n- InputType.JSON\n- InputType.DATE\n- InputType.SELECT\n\nAll these types correspond to Node-RED [TypedInput Widget](https://nodered.org/docs/api/ui/typedInput/#options-types) types,\nexcept for `InputType.PLAIN`, which uses a plain HTML input (you can set the type of the input using the `plain_type` argument).\n\nExample:\n```python\n@nodeforge_app.api_node('/todos/<int:todo_id>', method='PUT', parameters_config=[\n 'str:text',\n 'date:due-date',\n 'bool:done',\n NodeParameter('notes', type=InputType.PLAIN, plain_type='textarea'),\n 'int:level',\n NodeParameter('tags', options=['work', 'personal', 'chore', 'family'], multiple_select=True),\n NodeParameter('assigned-to', options=['me', 'you', 'him', 'her']),\n NodeParameter(name=\"pretty\", type=InputType.BOOL, default=True, url_param=True),\n])\n@flask_app.route('/todos/<int:todo_id>', methods=['PUT'])\n@require_authentication\ndef update_todo(todo_id):\n todo = next((item for item in todos if item['id'] == todo_id), None)\n if todo:\n data = request.get_json()\n\n todo.update({\n 'text': data.get('text', todo['text']),\n 'done': data.get('done', todo['done']),\n 'due-date': data.get('due-date', todo['due-date']),\n 'tags': data.get('tags', todo['tags']),\n 'notes': data.get('notes', todo['notes']),\n 'level': data.get('level', todo['level']),\n 'assigned-to': data.get('assigned-to', todo['assigned-to'])\n })\n\n return jsonify({'todo': todo})\n else:\n return jsonify({'message': 'Todo not found'}), 404\n```\nThis code will generate a custom node with the following edit view:\n![Edit view screenshot for the previous example](/doc/images/example2.png)\n\n## JSON Body Request\nIf a body parameter (neither `route_param` nor `url_param` is set to True) is included in the node config, a JSON body property is added to the custom node.\nIf this field is filled, body parameters from the form will be ignored, giving the user a way to send custom objects.\n\n![JSON Body Request Screenshot](/doc/images/json_body.png)\n\n### Generating Custom Nodes\nAfter configuring the nodes, you can generate them using the `output_package` method:\n\n```python\nnodeforge_app.output_package('/modules')\n```\n\nThis will create a package directory under `/modules` with the prefix \"node-red-contrib-nodered-forge-\" unless the `package_name` is specified in the initialization of `NodeForgeApp`.\n\nTo install the generated module in Node-RED, run the following commands:\n\n```bash\ncd /path/to/node-red/data/\nnpm install /modules/package-name\n```\n\nRestart Node-RED if the module is installed or updated.\n\n## Test App\nAn example app can be found under `dev/test-api-docker/test_api_app.py`, which is a dummy todo manager with CRUD operations. There is also a Docker Compose file with both this app and Node-RED to test the app; don't forget to restart upon making changes to the test app.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "NodeRedForge is a Python-based tool designed to facilitate the generation of custom JSON API nodes for Node-RED. By Khalid Grandi (github.com/xaled).",
"version": "1.0.0",
"project_urls": {
"Homepage": "https://github.com/xaled/nodered-forge"
},
"split_keywords": [
"library",
"node-red",
"code-generator"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1598db6f5840fecd64a51b62e3a83386c2846663afb9ad91dabedad1ca3914a7",
"md5": "698ed79b97a554c91cdcf17807fcd7bc",
"sha256": "d9dfbd27d5752e9b3b3547edca1d99062d69b4e7b13f0f9fb7865bbf09a30d0a"
},
"downloads": -1,
"filename": "nodered-forge-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "698ed79b97a554c91cdcf17807fcd7bc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3",
"size": 14674,
"upload_time": "2024-01-18T11:24:05",
"upload_time_iso_8601": "2024-01-18T11:24:05.964980Z",
"url": "https://files.pythonhosted.org/packages/15/98/db6f5840fecd64a51b62e3a83386c2846663afb9ad91dabedad1ca3914a7/nodered-forge-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-01-18 11:24:05",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "xaled",
"github_project": "nodered-forge",
"github_not_found": true,
"lcname": "nodered-forge"
}