API Files
Requiring External Requests
Some plugins are required to make external API calls in order to function. To assist in this matter, creating an api.py
file can be used to make calls to an external API that are utilised by the plugin and also be used in parsing the responses from the API.
Typically, it is best to organize utility files such that the api.py
file is inside a new directory called utils
within the plugin structure to maintain a standardized and organized framework. This helps the code within this file to be easily accessible by any action, trigger, or connection.
example-plugin/example-plugin/utils/api.py
python
1import requests2from insightconnect_plugin_runtime.exceptions import PluginException3import json45class ExamplePluginAPI:6def __init__(self, logger):7self.logger = logger8self.url = "https://www.example-url.com/api/v1"910def _call_api(self, method, url, params=None, json_data=None):11try:12# Make the API call13response = requests.request(method, url, json=json_data, params=params)1415# Usually, 204 returns None if successful16if response.status_code == 204:17return None18# All other 200 codes, return response.json()19if response.status_code in range(200, 300):20return response.json()21# Handle errors and raise PluginException22if response.status_code == 404:23raise PluginException(preset=PluginException.Preset.NOT_FOUND)24if response.status_code == 500:25raise PluginException(preset=PluginException.Preset.SERVER_ERROR)26if response.status_code == 503:27raise PluginException(preset=PluginException.Preset.SERVICE_UNAVAILABLE)28if response.status_code >= 400:29response_data = response.json()30raise PluginException(preset=PluginException.Preset.UNKNOWN, data=response_data.message)31# Handle JSON errors32except json.decoder.JSONDecodeError as exception:33self.logger.info(f"Invalid JSON: {exception}")34raise PluginException(preset=PluginException.Preset.INVALID_JSON, data=response.text)35# Handle HTTP errors36except requests.exceptions.HTTPError as exception:37self.logger.info(f"Call to Example API failed: {exception}")38raise PluginException(preset=PluginException.Preset.UNKNOWN, data=response.text)394041def list_users(self) -> str:42return self._call_api("GET", "users/list")4344def add_user(self, params):45return self._call_api("POST", "users/add", params=params)4647# etc
This example uses the Requests module to make an external API call, attempts to handle any errors arising from unexpected responses, and returns the result of the HTTP request.
In this file we define a class to contain the functions and logic necessary to interact with our chosen API.
By creating individual functions for each request such as the list_users method, which calls upon the _call_api function, we can simplify our API access logic.
Responses are also handled using PluginException, InsightConnects custom exception type which allows for a standardized response for plugin users and debugging.
Using the API File to Send Requests
To utilize these requests we can use the created API class as a property of the Connection class within the connection.py file created when the insight-plugin create command was first run.
python
1import insightconnect_plugin_runtime2from .schema import ConnectionSchema, Input34# Custom imports below5from example_plugin.util.api import ExampleAPI678class Connection(insightconnect_plugin_runtime.Connection):9def __init__(self):10super(self.__class__, self).__init__(input=ConnectionSchema())11self.client = None1213def connect(self, params):14self.logger.info("Connect: Connecting...")1516# Retrieve all inputs17account_id = params.get(Input.ACCOUNT_ID)18client_id = params.get(Input.CLIENT_ID)19client_secret = params.get(Input.CLIENT_SECRET, {}).get("secretKey")2021# Connect to API22self.example_api = ExampleAPI(23logger=self.logger,24account_id=account_id,25client_id=client_id,26client_secret=client_secret,27)2829def test(self):30return {"success": True}
In this example, we’ve assigned our ExampleAPI class to the client property of our connection.
We’re now able to access these API contact methods from our action files run
method and return the response to complete the plugin action.
python
1import insightconnect_plugin_runtime2from .schema import GetUsersInput, GetUsersOutput, Input, Output, Component345class GetUsers(insightconnect_plugin_runtime.Action):67def __init__(self):8super(self.__class__, self).__init__(9name="get_user",10description=Component.DESCRIPTION,11input=GetUserInput(),12output=GetUserOutput())1314def run(self, params={}):15# Get input from schema16user_id = params.get(Input.USER_ID)17# Call function from api.py file18users = self.connection.client.list_user_by_id(user_id)19# Map schema to output20return {Output.USERS: users}
Individual plugin authors are responsible for writing the api.py code.