Reactors
Reactors are stateless collections of methods that can perform actions inside Hantera based on input. Reactors can be used to create custom APIs and automate background work.
A Reactors starts with a Component that is then configured as a Reactor instance. This makes Reactor components re-usable for many different use-cases.
Reactors can be scheduled in Jobs or invoked directly through it’s public API, turning them into custom API endpoints to your Hantera installation.
Reactors methods can take arguments, and return values. Given the nature of Reactors, besides being a bridge between Hantera’s Actors and the outside world, they can often replace serverless functions provided by many of today’s cloud providers.
A Simple Example
To get a better idea of what a Reactor looks like, take a look at the below Reactor Component:
export create(args) =>
let deliveryId = newid
let channel = registry->$'channels/{args.channelKey}'
let orderCommands = [{ type = 'setChannelKey' value = args.channelKey },{ type = 'createDelivery' deliveryId = deliveryId }]
let orderLineCommands = args.items select i => { type = 'createOrderLine' deliveryId = deliveryId productNumber = i.productNumber quantity = i.quantity }
from channel match nothing |> 'Channel not found' { currencyCode: not nothing, taxIncluded: bool } |> messageActor( 'order' 'new' [{ type = 'create' body = { currencyCode = channel.currencyCode taxIncluded = channel.taxIncluded commands = [orderCommands, orderLineCommands] flatten } }] ) |> 'Something went wrong'
This reactor provides a creates a simple API to create orders based on channel settings. The export
statement creates a public method that we can call.
Testing the Reactor
In order to test this reactor, we must first install the component in Hantera. For the sake of this guide, we will use a manifest file and push the component to Hantera using hantera-cli. We will then create the Reactor instance itself using another manifest file referencing the newly created component. By instantiating the reactor we make it possible to call it or schedule it using a Job.
-
Start by creating the manifest file for Reactor component:
h_manifest.yaml uri: /resources/components/order.hreactorspec:codeFile: order.hreactor -
Next, let’s add the manifest that will instantiate the Reactor resource to the above file:
h_manifest.yaml ---uri: /resources/reactors/orderspec:componentId: order.hreactor -
To allow us to test, we should also define a channel so the reactor can actually create an order:
h_manifest.yaml ---uri: /resources/registry/channels/WEB_SEspec:value:currencyCode: 'SEK'taxIncluded: true -
Now let’s apply the manifests to our Hantera instance:
Terminal window h_ manage apply h_manifest.yaml -
You should now have a new Reactor resource live in your Hantera. You can verify it by querying the Reactors API. This should return metadata about the Reactor and it’s available methods:
GET https://<hantera-hostname>/resources/reactors/orderAuthorization: Bearer <YOUR TOKEN>Terminal window curl -i -X GET \https://<hantera-hostname>/resources/reactors/order \-H 'Authorization: Bearer <YOUR TOKEN>'Terminal window Invoke-WebRequest `-Uri "https://<hantera-hostname>/resources/reactors/order" `-Method GET ` `-Headers @{Authorization="Bearer <YOUR TOKEN>"} -
Once you have verified that the Reactor is there, you can now call the method using the API:
POST https://<hantera-hostname>/resources/reactors/order/createAuthorization: Bearer <YOUR TOKEN>Content-Type: application/json{"channelKey": "WEB_SE","items": [{"sku": "prod1","quantity": 1}]}Terminal window curl -i -X POST \https://<hantera-hostname>/resources/reactors/order/create \-H 'Authorization: Bearer <YOUR TOKEN>' \-H 'Content-Type: application/json' \-d '{"channelKey": "WEB_SE","items": [{"sku": "prod1","quantity": 1}]}'Terminal window Invoke-WebRequest `-Uri "https://<hantera-hostname>/resources/reactors/order/create" `-Method POST ` `-Headers @{Authorization="Bearer <YOUR TOKEN>"; 'Content-Type'="application/json"}-Body '{"channelKey": "WEB_SE","items": [{"sku": "prod1","quantity": 1}]}'
That’s it. Notice how the method name defined in the Reactor component code is manifested in it’s public API, while we can name the Reactor anything we want in the actual Reactor resource.
To see the complete example, visit the Cookbook.
Access Control
You may wonder, how is it safe to make arbitrary external requests available through the public API. This sounds like a recipe for all kinds of denial-of-service problems.
While it’s true that Reactors are powerful and used wrong it can be misused. Reactors are tightly integrated with Hantera’s access control layer, which means that calling Reactor Methods require explicit permission for the session. Additinally, as opposed to many other similar platforms, Hantera makes all effects of Reactors very easy to monitor through the Reactor Logs.
The ACE pattern for reactors looks like this:
reactor[/<id>][/<method>]:read|write|invoke