Skip to Content

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

import requests from insightconnect_plugin_runtime.exceptions import PluginException import json class ExamplePluginAPI: def __init__(self, logger): self.logger = logger self.url = "https://www.example-url.com/api/v1" def _call_api(self, method, url, params=None, json_data=None): try: # Make the API call response = requests.request(method, url, json=json_data, params=params) # Usually, 204 returns None if successful if response.status_code == 204: return None # All other 200 codes, return response.json() if response.status_code in range(200, 300): return response.json() # Handle errors and raise PluginException if response.status_code == 404: raise PluginException(preset=PluginException.Preset.NOT_FOUND) if response.status_code == 500: raise PluginException(preset=PluginException.Preset.SERVER_ERROR) if response.status_code == 503: raise PluginException(preset=PluginException.Preset.SERVICE_UNAVAILABLE) if response.status_code >= 400: response_data = response.json() raise PluginException(preset=PluginException.Preset.UNKNOWN, data=response_data.message) # Handle JSON errors except json.decoder.JSONDecodeError as exception: self.logger.info(f"Invalid JSON: {exception}") raise PluginException(preset=PluginException.Preset.INVALID_JSON, data=response.text) # Handle HTTP errors except requests.exceptions.HTTPError as exception: self.logger.info(f"Call to Example API failed: {exception}") raise PluginException(preset=PluginException.Preset.UNKNOWN, data=response.text) def list_users(self) -> str: return self._call_api("GET", "users/list") def add_user(self, params): return self._call_api("POST", "users/add", params=params) # 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.

import insightconnect_plugin_runtime from .schema import ConnectionSchema, Input # Custom imports below from example_plugin.util.api import ExampleAPI class Connection(insightconnect_plugin_runtime.Connection): def __init__(self): super(self.__class__, self).__init__(input=ConnectionSchema()) self.client = None def connect(self, params): self.logger.info("Connect: Connecting...") # Retrieve all inputs account_id = params.get(Input.ACCOUNT_ID) client_id = params.get(Input.CLIENT_ID) client_secret = params.get(Input.CLIENT_SECRET, {}).get("secretKey") # Connect to API self.example_api = ExampleAPI( logger=self.logger, account_id=account_id, client_id=client_id, client_secret=client_secret, ) def test(self): return {"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.

import insightconnect_plugin_runtime from .schema import GetUsersInput, GetUsersOutput, Input, Output, Component class GetUsers(insightconnect_plugin_runtime.Action): def __init__(self): super(self.__class__, self).__init__( name="get_user", description=Component.DESCRIPTION, input=GetUserInput(), output=GetUserOutput()) def run(self, params={}): # Get input from schema user_id = params.get(Input.USER_ID) # Call function from api.py file users = self.connection.client.list_user_by_id(user_id) # Map schema to output return {Output.USERS: users}

Individual plugin authors are responsible for writing the api.py code.