ForrestJS API » Register Action

ForrestJS API » Register Action


Register Action

You need to register an Action to an Extension to add functionalities to a ForrestJS App.

Use the registerAction() API inside a Service or Feature's Manifest function:

const myFirstFeature = ({ registerAction }) => {
  registerAction({
    target: '$INIT_FEATURE',
    handler: () => console.log('My First Feature'),
  });
};

🧐 The piece of code above just writes a console.log App's Boot Lifecycle. It's not much, but it is already a viable piece of business logic.


💻 Live on CodeSandbox:
https://codesandbox.io/s/register-action-v64r4?file=/src/index.js:118-222


Register Multiple Handlers

A ForrestJS' Extension is just a named pointer to a list of Action handlers.
They are just regular JavaScript functions, really.

Every time you register an Action, you simply add yet another handler to the Extension's list.

registerAction({
  target: '$INIT_FEATURE',
  handler: () => console.log('Handler #1'),
});

registerAction({
  target: '$INIT_FEATURE',
  handler: () => console.log('Handler #2'),
});

You can register multiple Action Handlers to the same Extension.
👉 DON'T PUT EVERYTHING IN THE SAME FUNCTION

Modularity is gold!


💻 Live on CodeSandbox:
https://codesandbox.io/s/register-action-v64r4?file=/src/index.js:226-400


The Handler Priority

Sometimes, you just need to be sure that a specific piece of logic runs before or after something else.

This is mostly the case when 2 services establish some kind of soft-dependencies towards each other. We faced this situation while building our PostgreSQL Connection Service, and integrating it with the Fastify Service.

Here is a simple example where 2 Features register an Action into the very same Extension. Then they are listed into the App's features in the same order as they are written:

const firstFeature = {
  target: '$INIT_FEATURE',
  handler: () => console.log('Init First Feature'),
};

const secondFeature = {
  target: '$INIT_FEATURE',
  handler: () => console.log('Init Second Feature'),
};

forrestjs.run({ features: [firstFeature, secondFeature] });

The result of this application would be:

Init First Feature
Init Second Feature

Play with the priority option in order to revert the output without changing the listing order:

const firstFeature = {
  target: '$INIT_FEATURE',
  handler: () => console.log('Init First Feature'),
  priority: -1,
};

const secondFeature = {
  target: '$INIT_FEATURE',
  handler: () => console.log('Init Second Feature'),
  priority: 1,
};

forrestjs.run({ features: [firstFeature, secondFeature] });

The result of this application is now:

Init Second Feature
Init First Feature

The Action Handlers registered to the same Extension are sorted from the higher Priority to the lower. The default Priority is 0 and you can play with this option so to affect the execution order independently from the listing order.

IMPORTANT: You shouldn't abuse of this possibility though. You should always strive to build truly unentangled Services or Features that don't rely on one another.


💻 Live on CodeSandbox:
https://codesandbox.io/s/register-action-with-priority-yuibn


Action Meta Information

You can pass other options along with your Action's target and handler.

The info you pass may be used for debugging or tracing purpose by the Service or Feature that creates the Extension.

There is still a lot of work-in-progress in improving the App isolation and error tracing of Extensions using those Action Meta Information. For now, you can find some examples in this SandBox:


💻 Live on CodeSandbox:
https://codesandbox.io/s/register-action-options-ey8h0


target

type:    String

It is the name of the Extension that you want to integrate into.

It could be just a plain string, but usually you will use a formal dictionary of available Extensions by simply using the $ prefix:

registerAction({
  target: '$INIT_FEATURE',
});

In this case $INIT_FEATURE is not just a string, but it will be matched against a formal dictionary, verified, and translated to the absolute Extension name string.

👉 Try to misspell it, you will see that the App crashes at boot time.

You can use this feature even if you are not sure that a particular Extension will be available. It's a common scenario when you enable/disable Features at boot time based on feature flags or similar mechanisms.

In such a case, you can use the Optional Target signature:

registerAction({
  target: '$THIS_MAY_NOT_EXISTS?',
});

NOTE: Formal targets are all uppercase... just because they look like constants (which they are under the hood). It is just a convention.

handler

type:    Function | Array | Object

The Action Handler is often a regular JavaScript function that takes 2 arguments:

const actionHandler = (extensionContext = {}, appContext = {}) => {};
  • the Extension's Context is an object with custom data and API provided by the logic that creates the Extension. Is the Extension's way to pass parameters to the Action handlers.
  • the App Context is the full set of ForrestJS APIs, plus application data or additional APIs that are shared by Services and Features.

name

type:    String

The Action's Name gives a logical identification of the Action inside the App.

When you pack Actions as Features or Services with a functional Manifest, the Action's name is defaulted to the Manifest's name.

priority

type:    Integer
default: 0

It set the execution order of the Action handlers that are registered to an Extension.

trace

type:    Any

It's an arbitrary information that will be returned into any Error generated by the Action Handler. I ususally set it to __filename because errors in JavaScript suck.

results matching ""

    No results matching ""