As discussed, Connection represents the most common parameters necessary to run your integration.
```python python PASSWORD = ConnectionParam("PASSWORD", description="Password for JIRA")
Definition of Connection Param class i.e. all the parameters it accepts. ```python class ConnectionParam: id: str description: str label: str default=None optional: bool=False, options=None, data_type=DataType.STRING, # Options: STRING, NUMBER, BOOL, INT, JSON input_type=InputType.TEXT # Options: TEXT, TEXT_AREA, EMAIL, PASSWORD, SELECT, FILE, ENCRYPTED_FILE
- Default - Represents the default value of the parameter, transforming it into an optional parameter, expressed as a string.
- Optional - Indicates whether the parameter is optional or mandatory.
- Options - If the parameter's input type is
Select
, you can define the available options here json
options = [ { "label": "Api Key", "value": "api_key" }, { "label": "Api Key", "value": "api_key" } ] ``` - **Data Type** - how do you want to parse the data. i.e. as a String, Number(float), Boolean, Int, Json. - **Input Type** - These refer to HTML tags that determine the appropriate rendering for each field. - **Text** - Represents a small text field. - **TextArea** - Represents a large text field spanning multiple lines. - **Password** - Represents a text field with a hidden value. - **Select** - Represents a dropdown menu. - **Files** - Represents the option for uploading a file. - **Encrypted File** - Represents the option for uploading a file without revealing its text value (useful in cases where the file contains sensitive information). > Note: > > The parameters mentioned above are only recognized within the class constructor and are not parsed from the docstring. All the aforementioned fields must be provided during the definition of Connection and Action parameters. It's okay if you don't have any common parameter. But, we need at least a single action to be defined. So, following will be the bare bone custom integration. ```python python # A top level __doc__ string in any of the files can be used to set meta information for the entire integration. # Information in required format must be specified in only one of the files (any one file). # Other files can contain __doc__ strings but it shouldn't be in the following format so that meta information is picked up in a predicatable manner. """ name: Custom Integration description: Custom Integration Description logoUrl: https://s3.amazonaws.com/lhub-public/integrations/default-integration-logo.svg """ # `lhub_integ` is already installed as a dependency in the container # For testing, you can do `pip install -e <path to backend/custom-integrations/lhub-integ` from lhub_integ.params import ConnectionParam, ActionParam from lhub_integ import action # ConnectionParams must be declared at the top level. # To get the value of the Parameter call param_name.read() # ConnectionParam can take the values `optional=[True/False]` and `default="some_default_string"` """ ConnectionParam and ActionParam must be called with an identifier Other optional named parameters: description="description shown in the UI" label="label shown for parameter in UI" optional=[True/False] default="some_default_string" Advanced usage: data_type=DataType.[STRING/COLUMN/NUMBER] - defaults to STRING input_type=InputType.[TEXT/TEXT_AREA/EMAIL/PASSWORD/SELECT/COLUMN_SELECT] - defaults to TEXT options= [list of options in a drop down] """ PASSWORD = ConnectionParam("PASSWORD", description="Password for JIRA") URL = ConnectionParam("URL", description="URL for the server") @action def process(): return { "shared_action_param": URL.read() }
The connection parameters defined above comes as input while creating connection
Connection Validator:
Write a function and annotate it with @connection_validator
. This option checks the validity of the connection. For example, you can check whether the input credentials entered by the integration user are valid.
For Slack Integrations, you can make an API call (using the requests library) to check whether the value entered by the user for Incoming Webhook URL
is valid.
Note
Utilities are available to perform validity or sanity checks, including validations
, input_helpers
, and helpers
. You can explore them or you can write your own sanity checks
import requests from lhub_integ import connection_validator from lhub_integ.common import helpers, validations from lhub_integ.params import ValidationError from typing import Optional, List def post_message_on_slack(incoming_webhook, message, channel_name=''): payload = {'text': message} if channel_name: payload['channel'] = channel_name response = requests.post(incoming_webhook, json=payload, headers={'Content-Type': 'application/json'}) response.raise_for_status() @connection_validator def validate_connections() -> Optional[List[ValidationError]]: if not SLACK_INCOMING_WEBHOOK.read(): return [ValidationError(message="Parameter must be defined", param=SLACK_INCOMING_WEBHOOK)] try: post_message_on_slack(SLACK_INCOMING_WEBHOOK.read(), 'This is a test message from LogicHub, Inc.') except Exception as ex: return [ValidationError(message=f"Incorrect Parameter: {repr(ex)}", param=SLACK_INCOMING_WEBHOOK)]
The function annotated with the connection_validator
decorator must return either an empty array or None
. In the case of errors, it should return an array of ValidationError
.
Dynamic Connection Params
If an integration requires dynamic descriptors based on connection, they can be implemented (in your main.py file) as shown in the below example:
```python main.py import json from lhub_integ.common import input_helpers from lhub_integ import connection_validator
def override_action_descriptors(): descriptor_json = input_helpers.get_stripped_env_string('__integration_descriptor')
# Custom value to be overridden at connection validation new_description = "My Custom Dynamic Description" descriptor = json.loads(descriptor_json) actions = descriptor['actions'] actions[0]['instantiation']['steps'][0]['inputs'][0]['description'] = new_description return {"actionOverrides": actions}
@connection_validator def validate_connections(): result = json.dumps(override_action_descriptors()) print("[result] {}".format(result)) ```