Custom Plugin Deployment

Overview

To register for a callback from BioT, you (the developer) must supply BioT with a callback endpoint URL. The URL can be of an API that resides anywhere in the world and does not have to be hosted in the AWS cloud.

You have 3 options to deploy a plugin:

  • Using the Plugin Configurations page in the BioT Console, which provides a UI for uploading, updating, and deleting plugins without API calls.
  • Using the BioT plugin deployment API, which deploys your plugin in the same VPC as the platform.
  • Deploying the plugin under your own account and supplying BioT with a URL to call when the plugin needs to be invoked

To make sure the plugin responds quickly to BioT calls, it is recommended to use the first option.

Deploying Under the BioT Account

Deploying under the same account that hosts the BioT platform has several benefits:

  • Almost no latency between BioT and the implementation.
  • You will not have to use two cloud accounts to manage your cloud solution.
  • All security configurations will be handled by BioT.

The following restrictions apply when deploying under the BioT account:

  • The solution must be compatible with and based on the AWS Lambda solution.
  • The plugin will only have network access and will not be able to access other AWS services like RDS, S3, etc.

Plugin Prerequisites

By default, BioT assumes several parameters about the plugin:

  • Plugin Architecture: x86_64
  • Ephemeral storage: The size of the function’s /tmp directory is set to 512 MB.
  • Memory Size: 128 MB
  • Runtime environment: nodejs16.x
  • Timeout: Max execution time 3 seconds
  • Main file name: index.js
  • Main function name: handler()

*When uploading a Docker image, the runtime and function handler will be displayed as null. Their values are taken from the Dockerfile.

You can update some of these values:

  • The runtime engine can be set to one of the supported values.
    Use the "Identifier" value from the list in the following link:
    Lambda runtimes
  • The main function name can be changed from handler().
  • The Lambda timeout can be changed from 3 seconds. The max value is 900 seconds.
  • The Lambda memory can be increased from 128MB
📘

First Time Deployment

If during the first plugin deployment you do not supply a zipped plugin code, the platform will use default plugin code that can be found here.
When you feel that you are ready to make modifications, clone this repository, modify it and zip it.
Supply the zip file during the plugin deployment and it will override the old deployed plugin.

Plugin Deployment

Plugin deployment for a zip file is composed of the following stages:

  1. Clone our sample code
  2. Update the code with your required changes
  3. Zip the code
  4. Make a create plugin API call

Plugin deployment for Docker is composed of the following stages:

  1. Call the /settings/v2/plugins/docker-repository/temp-credentials API and keep the response JSON. Will be valid for 1 hour.
  2. Clone our sample code
  3. Update the code with your required changes
  4. Run login.bat/sh script
  5. Run BuildAndPush.bat/sh script and keep the "imageTag"
  6. Make a create plugin API call with the additional "imageTag": "string" and deploymentPackageType":"IMAGE" keys added into the config parameter.

Plugin API call

Make the following API call:
POST https://your-domain.com/settings/v2/plugins

This is a "multipart/form-data" request that includes both the binary zip file and configuration information. See here for more details.

The form should include 2 parameters:

  1. "code": the binary zip file - this is optional, and if not supplied, the API will use the sample code as a default "seed" plugin. For a Docker image, this is not relevant, and you don't need to pass this parameter.
  2. "config": JSON configuration of the plugin.

This is an example of a multi-part call.
The first section describes the zip file and then passes the zip file content. The second part is the configuration.

-----------------------------
Content-Disposition: form-data; name="code"; filename="hw.zip"
Content-Type: application/x-zip-compressed

<ZIP_BINARY_DATA>
-----------------------------
Content-Disposition: form-data; name="config"

{
   "name":"demo_plugin",
   "displayName":"Demo Plugin",
   "version":"2",
   "timeout": 10,
   "handler": "index.main",
   "runtime": "python3.10",
   "environmentVariables":{
      "var1":"val1",
      "var2":"val2",
      "var3":"val3"
   },
   "subscriptions":{
      "interceptionOrder":"2",
      "interceptions":[
         {
            "type":"POST_REQUEST",
            "apiId":"POST/organization/v1/users/patients",
            "entityTypeName":"<String>",
            "order":"5"
         }
      ],
      "notifications":[
         {
            "entityTypeName":"<String>",
           	"actionName":"<String>",
						"templateName":"<String>"
         }
      ]
   }
}
ParameterDescriptionFormat
nameUnique plugin name. The prefix "Plugin-" will be added to it. Mandatory.String
displayNameThe display name of the plugin. It will be added to the environment variables with a reserved key. Mandatory.String
versionThe plugin version number. Mandatory.Integer
environmentVariablesA map that contains environment variables as key-value pairs, keys starting with "BIOT_" are reserved for system use. Optional.JSON
interceptionOrderThe order in which this plugin will be executed if more than one interceptor exists for the API. This parameter applies to all interceptors and should be greater than 1. Mandatory.Integer
interceptionsA list of interceptor APIs that this plugin will handle. Optional.JSON
interceptions.typeThe type of the interceptor: PRE_REQUEST (Modify the request), POST_REQUEST (Modify the response), ADAPT_ENTITY (Modify the entity - see entityName description below). MandatoryString
interceptions.apiIdThe ID of the API that you want to subscribe to. This only applies to PRE_REQUEST & POST_REQUEST types. For possible values, see the API documentation for the service you are subscribing to. For example: POST/organization/v1/users/patients. OptionalString
interceptions.entityTypeNameThe entity name that you want to modify. Provided only if type=ADAPT_ENTITY. For possible values, see the API documentation for the service you are subscribing to. For example: patient. OptionalString
interceptions.orderOverride for the interceptionOrder parameter. Optional.Integer
notificationsA list of notification APIs that this plugin will handle. Optional.JSON
notifications.entityTypeNameThe entity type that you would like to be notified about. See the [API documentation] for available values. Mandatory.String
notifications.actionNameThe action performed on the entity that you would like to be notified about. See the [API documentation] for available values. Mandatory.String
notifications.templateNameThe name of the template to subscribe to. When specified, the plugin is triggered only for events on entities of that specific template. Optional.String
deploymentPackageTypeThe deployment package type of the plugin. Cannot be changed after the creation. The default is ZIP. Values: ZIP, IMAGEString
imageTagA string that represents the Docker image in the AWS repositoryString

Generic Entities V3 Required

The notifications.templateName parameter is only supported when using the Generic Entities V3 API. If you are still using the V1 API, you must migrate to V3 before using template-specific notification subscriptions. For more information, see Using Generic Entities. To enable V3 for your environment, contact BioT Support.


If successful, the return value will be 201 Created with a JSON describing the newly created plugin.

{
   "name":"demo_plugin",
   "displayName":"Demo Plugin",
   "version":"2",
   "environmentVariables":{
      "var1":"val1",
      "var2":"val2",
      "var3":"val3"
   },
   "subscriptions":{
      "interceptionOrder":"2",
      "interceptions":[
         {
            "type":"POST_REQUEST",
            "apiId":"POST/organization/v1/users/patients",
            "entityTypeName":"<String>",
            "order":"5"
         }
      ],
      "notifications":[
         {
            "entityTypeName":"<String>",
            "actionName":"<String>"
         }
      ]
   },
  "enabledState": "DISABLED",
  "cronSchedule": "45 1/12 1-5 JAN,OCT ? *",
  "deploymentPackageType": "ZIP",
   "endpointUrl":"https://aws.....",
   "linkToConsole":"https://aws.....",
   "creationTime":"2022-11-09T14:22:01.879Z",
   "lastModifiedTime":"2022-11-09T14:22:01.879Z"
}
ParameterDescriptionFormat
endpointUrlThe endpoint URL for the newly created pluginString
linkToConsoleDirect link to the AWS console where the plugin was deployedString

Clone our sample code

See plugin sample code

Update the code with your required changes

Use your favorite IDE to make modifications to the code.
We encourage you to use your own GIT repository to track changes to the sample plugin and later on automate plugin deployment.

Zip the code or create docker image

Zip the code by zipping the root directory of the plugin. You need to omit the .git and git ignore files if the plugin code stored in a GIT repository.

For docker image build and push image to get "imageTag" to include in your update plugin API call.

Make an update plugin API call

Updating a plugin is very similar to creating it. Prepare your plugin code and zip in the same way you first created it.
Make the following API call:
PUT https://your-domain.com/settings/v2/plugins/{name}

The request body and response are the same as in the plugin creation.
See here

Plugin Deletion

To delete a plugin, make the following API call:
DELETE https://your-domain.com/settings/v2/plugins/{name}

🚧

Note

When calling the DELETE plugin API you need to add "Plugin-" prefix to its name.
For example if the plugin name is "add_data", you need to pass "Plugin-add_data" to the API call.

The deletion process will remove the code from the cloud and all the interceptors and notifications associated with it.

Deploying Under Your Own Account

If you decide to deploy your code under your own account, then there will be no restrictions on the way the callback should be implemented.
The only requirements are that the exposed URL is HTTPS and public, and that there are no security measures that will block BioT from reaching this endpoint URL.
Securing the communication between BioT and the function code will be done by utilizing JWT. BioT will send a signed token that will have to be verified by the function before executing its custom code.

To register your external service for BioT events, see Interception and Notification Subscription.
Also, for the plugin to be able to make API calls to BioT, you'll have to create a service user and use its credentials from inside the plugin. Refer to the service user documentation for more information.