Dependent Collections

In the following example, the sf_perform_request function will be used to develop a custom step. It will take a list of URIs as its input, make multiple GET requests, and output its data as a Python dictionary. From there we will further extract out the device category GUIDs and category names.

To do this, I am going to be using the sf_perform_request function available in the REST: Toolkit. This function enables making one or more HTTP requests within a custom step. We will use the sf_perform_request inside our custom step called multi_http. See below for sf_perform_request usage.

silo.low_code_steps.rest.sf_perform_request(request, debug, step_args=None)

Perform an HTTP request from within the Snippet Framework

This entrypoint enables calling the HTTP requestor from within the Snippet Framework by only requiring the ResultContainer to be present. It will use all logic from the HTTPRequestor without being called as a step. This is helpful if you have a custom step that needs to utilize the HTTPRequestor as a stand-alone call.

If step_args are specified, it will use these values instead of the current current_config within the ResultContainer.

If not specified, this will attempt to auto-convert based on the returned headers from the request. If you do not want to auto-convert the result, you must specify convert=False within the step_args that are being utilized during execution.

Parameters:
  • request (silo.low_code.ResultContainer) – Result container to collect

  • debug (callable) – AppLogAdapter’s debug function

  • step_args (dict) – Arguments to use for the HTTP request. If this is value is None, the ResultContainers step_args will be used.

Return type:

http.http_response

I am going to start with the API’s initial payload. It is accessible via a GET at api/device_category. The response has a key called result_set that holds a list of URI elements. We will need to select it and then make our HTTP GET requests.

api/device_category’s payload:

{
  "searchspec": {},
  "total_matched": 119,
  "total_returned": 100,
  "result_set": [
    {
      "URI": "/api/device_category/88",
      "description": "Cloud"
    },
    {
      "URI": "/api/device_category/10",
      "description": "Cloud.Account"
    },
    {
      "URI": "/api/device_category/116",
      "description": "Cloud.Analytics"
    }
  ]
}

Using JSONPath, I will return a list of the URIs. This will be the input into the multi_http step. Below is an example of making a GET request on one of these URIs.

api/device_category/88’s payload:

{
  "guid": "AD49E0B5AB7073B6927C4607C5F83833",
  "ppguid": "7A7322AA30F189B42943C082EFD71217",
  "cat_name": "Cloud",
  "cat_icon": "/em7/libs/map_icons/cloud.swf",
  "edit_date": "1667510932",
  "edit_user": "/api/account/1",
  "dashboard": "/api/device_dashboard/1",
}

Our end goal output is a list of tuples containing the guid and the cat_name from each payload. The custom step multi_http``will call ``sf_perform_request and combine all the JSON output into a list. From there we will use jmespath to access the desired keys.

Our Snippet Argument will look like this:

low_code:
  id: guids_by_category_names
  version: 2
  steps:
    - http:
        uri: "/api/device_category"
    - json:
    - jmespath:
        value: "result_set[*].URI"
    - multi_http:
    - jmespath:
        index: true
        value: "data[*].{_index: guid, _value: cat_name}"

The multi_http step will need to replace the URI in the step_args for our subsequent GET request. The step_args in http and sf_perform_request expects that the URI is contained in a dictionary whose key is uri. Each URI also needs to be reformatted to avoid duplicating “/api” in the path. This step will loop through replacing each URI parameter in the step_args. After each call to sf_perform_request we will append the parsed JSON into a list. See below for more information on http_response.

silo.low_code_steps.rest.http_response(response, converted)

HTTP response and converted output

Parameters:
  • response (Response) – requests.Response

  • converted (Union[dict,None]) – Auto-converted output i.e. json, xml, or None

This step will be added to our snippet under the section labeled User Editable. See below for its implementation.

from silo.low_code_steps.rest import sf_perform_request

@register_requestor
def multi_http(result, result_container, debug):
    """Executes multiple HTTP/HTTPs requests

    :param list result: URIs
    :param ResultContainer result_container: input into sf_perform_request
    :param callable debug: Debug function for a context-aware logger

    :return: responses
    :rtype: dict
    """
    data = []
    for request in result:
      # Remove extra "api" from request
      request = "/" + request.split('/', 2)[-1]
      http_resp = sf_perform_request(result_container, debug, step_args={"uri" : request})
      # Rely on auto-conversion feature for HTTP response JSON -> dict
      data.append(http_resp.converted)
    return {"data": data}