Product module code
Configure custom product logic in JavaScript
What is product module code?
Product module code is a low-code environment in which custom logic can be written for insurance products on the Root platform.
While some product functionality is configured in the general product settings, product module code allows you to build more complex business rules in JavaScript. This offers a large degree of flexibility in customising a product module to meet product requirements.
The platform references the product module code to execute customised functions (or hooks) relating to a specific event for your product. For example, when the quote API endpoint is called for your product, the platform will look in your product module code for the validateQuoteRequest()
and getQuote()
functions to execute.
Product module code is contained in multiple virtual JavaScript files. The published code is run by the platform in a secured Node.js virtual environment. Specific built-in Node.js globals, as well as external modules for dates, validation and API requests, are made available in this environment.
Root also enables a set of SDK methods to retrieve policy and related information directly from the platform's runtime environment, without having to route requests through the externally exposed API endpoints.
Type checking in JavaScript
By default, we add a VS Code setting to your product module code directory to enable type checking. This allows you to leverage some of TypeScript's type checking and error reporting functionality in regular JavaScript files - a great way to catch common programming mistakes.
These type checks use the type declaration files included under
code > types
andcode > unit-tests > types
.To turn off type checking, open the relevant
jsconfig.json
file and setcompilerOptions.checkJs
tofalse
.
Helper functions
Aside from the specific functions that correspond to individual hooks, you may need to define a wide variety of your own helper functions and constants to make the product module code efficient, readable, maintainable and testable. This is in the form of abstracted JavaScript functions. Helper functions make it easy to share logic with other hooks in the product module code.
Pricing and charges helpers
The platform relies on the getQuote()
function to generate a quote. This means the product module code will typically include functions to calculate the premium based on the rating factors (parameters relevant to pricing) received via the quote endpoint.
This could also include calculating variable cover amounts and other policy-specific information, depending on how the product has been designed to work.
Validation helpers
Helper functions can also be useful to perform additional validations. In some cases Joi validation schemas are not ideal for performing complex validations, especially where the validation of some parameters depend, in complex ways, on the value of other parameters. In these cases helper functions can be used to define custom validation of the input data.
To return error messages via the API in case of invalid input, the command throw new Error('<Error message>');
can be used in the product module code. This will halt execution and result in a 400 Bad Request
API response.
Miscellaneous helpers
Examples of other helper functions could be a function to calculate the policyholder's age from her ID number, or a function to merge data received at the quote and application stage into a single object.
Examples of constants could be a constant percentage to calculate commissions, or an array containing a list of valid country codes.
Environment variables
You can access the following Root-specific environment variables related to the context in which the product module code is run. This is useful when you need to execute environment-specific code, such as calling the staging or production instance of an external service depending on whether the product module code is executed for a sandbox or live policy.
Property | Definition |
---|---|
process.env.ENVIRONMENT | String. One of [sandbox , production ]. See the Overview guide for more details. |
process.env.ORGANIZATION_ID | String. The UUID of the organization. For example, for product module code hooks that are triggered by an API call, this will be the organization linked to the API key. |
process.env.ORGANIZATION_TIMEZONE | String. The organization timezone. |
process.env.API_TOKEN | String. An token that can be used authenticate requests to the Root API. See the Root API calls section below. |
process.env.API_BASE_URL | String. The host URL that can be used to construct URLs for requests to the Root API. See the Root API calls section below. |
Root globals
When the product module code is run by the platform, various classes and modules are passed to the virtual machine environment as globals. These globals can be referenced in the product module code without defining them explicitly.
Returned objects
The classes in the table below can be accessed as globals in the product module code. Specific functions in the product module code related to policy issuing and other lifecycle events return instances of these classes. For example, the getPolicy()
function returns an instance of the Policy
class. Typically, these response objects are also returned in JSON format via the corresponding API endpoint.
Class name | Guide | API reference |
---|---|---|
QuotePackage | Quote hook | Quote package object |
Application | Application hook | Application object |
Policy | Policy issue hook | Policy object |
AlterationPackage | Alteration hooks | Alteration package object |
AlteredPolicy | Alteration hooks | See the guide. |
ReactivationOption | Reactivation hook | See the guide. |
RequotePolicy (deprecated) | Requote hook | Requote policy endpoint |
Throwing errors
To throw an error from the product module code, simply throw a standard JavaScript error. For example,
throw new Error('Policyholder date of birth does not match age provided at quote step)
.The error message you specified will be returned in the API response, will be visible in the product module execution logs, and may be displayed to on the dashboard, depending on the context.
UUIDs
The following function generates a universally unique identifier (UUID).
const uuidString = createUuid();
External modules
Built-ins
The following built-in JavaScript modules can be accessed in the product module code:
Math
- Properties and methods for mathematical constants and functions. Useful, for example, for rounding currency values to the nearest integer in the product module codeJSON
- Methods for parsing JavaScript Object Notation (JSON) and converting values to JSON. Useful, for example, for making external API calls from the product module code.Promise
- Representing the eventual completion (or failure) of an asynchronous operation and its resulting value. Useful, for example, for making external API calls and calling the Root SDK methods.
Validation
Root enables the popular and powerful Joi validation library in the product module code. This is particularly useful for validating the product-specific input parameters received via your product's quote, application and alteration endpoints.
Note:
- Root currently supports version 11.3.4 of Joi. Methods released in later versions of Joi are not currently supported.
- The
Joi.date()
andJoi.string().isoDate()
methods have been customised by Root and therefore won’t work exactly as per the Joi docs. Please refer to the list of extensions below.
The Joi module used in the product module code includes a number of custom Root extensions for insurance applications. The available extensions are listed below.
Dates
Normally when you use the Joi.date()
and Joi.string().isoDate()
methods to validate inputs and the date input doesn't explicitly include the timezone offset, the offset is assumed to be UTC.
Root has customised these methods to use the organisation's timezone as the default if the timezone offset is not explicitly included in the date input being validated.
To override the timezone offset used as the default for the date input, you can either explicitly include the timezone offset in the date input (e.g. 2022-12-15T00:00:00+02:00) or you can pass the timezone as a parameter in the joi method schema (list of supported timezones).
// Organisation timezone used as default
const dateSchema = Joi.date();
const isoDateSchema = Joi.string().isoDate();
// New York timezone used as default
const dateSchema = Joi.date('America/New_York');
const isoDateSchema = Joi.string().isoDate('America/New_York');
ID number
This extension checks whether a string is a valid South African ID number.
const joiIdNumberSchema = Joi.string().idNumber();
IMEI
This extension checks whether a string is a valid 15-digit IMEI number. Dashes (the -
character) are not allowed.
const joiImeiSchema = Joi.string().imei();
Digits
This extension checks whether a string contains only digits between 0 - 9.
const joiDigitsSchema = Joi.string().digits();
JSON string
This extension checks whether a string represents valid JavaScript Object Notation (JSON).
Note: This method does not allow single '
quotes. Only escaped double quotes are allowed, e.g. { \"key\": \"value\" }
not { 'key': 'value' }
.
const joiJsonSchema = Joi.string().jsonString();
RFC email
This extension checks whether a string conforms to the RFC 5322 standard for email addresses.
const joiRfcEmailSchema = Joi.string().rfcEmail();
Validation of contact details does not guarantee correct input
Joi validation extensions like RFC email and cellphone are only a "first line of defence" against erroneous data input. The fact that these validation checks are passed does not guarantee that the correct data has been provided by the customer, or that this data was correctly captured (for example by a call centre agent).
Cellphone
Checks that a string is a valid South African phone number.
const joiCellphoneSchema = Joi.cellphone();
Date of birth
This extension checks the following:
- The value must be a string.
- The value must be parseable as a date in the specified format. If no format is specified, "YYYYMMDD" and "YYYY-MM-DD" will be attempted.
- The date must be equal to or earlier than the start start of the day the code is executed.
const joiDateOfBirthSchema = Joi.dateOfBirth().format("YYYY-MM-DD");
Dates
Root enables the moment.js library for working with dates in the product module code. This is useful, for example, for manipulating and setting policy start and end dates. Root currently supports version 2.29.4 of moment.js.
Note: The moment module available in the product module code is in UTC mode. This means that dates will be represented in and timezone offsets assumed as UTC. Please refer to the parsing docs and guide for more information.
const getPolicy = (application, policyholder) => {
// Function body omitted
return new Policy({
start_date: moment().format(),
end_date: moment().add(1, 'year').format(),
// Other properties omitted
});
}
Root also enables the moment-timezone extension which allows you to parse and display dates in any timezone. Root currently supports version 0.5.40 of moment-timezone.
const getPolicy = (application, policyholder) => {
// Function body omitted
return new Policy({
start_date: momentTimezone().tz('America/New_York').format(),
end_date: moment().tz('America/New_York').add(1, 'year').format(),
// Other properties omitted
});
}
API calls using node-fetch
node-fetch
Root enables the use of the node-fetch module for making API calls from within the product module code. This is a Node.js implementation of the JavaScript fetch API. Root currently supports version 2.6.0 of node-fetch.
Root API calls
You can authenticate requests to the Root API using an API token provided in the environment (process.env.API_TOKEN
). You can also use process.env.API_BASE_URL
to construct the path to the endpoint you intend to call. The example below is for a call to the List policy payments endpoint.
const response = await fetch(
`${process.env.API_BASE_URL}/v1/insurance/policies/${policy.policy_id}/payments`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'Authorization': `Bearer ${process.env.API_TOKEN}`,
},
}
);
checkForAPIErrors({ response });
const policyPayments = await response.json();
External API calls
You can also use node fetch to make calls to external APIs, for example if you expose a pricing engine to calculate the premium based on the rating factors.
const getNewPremium = async ({ requestBody }) => {
const response = await fetch('https://domain.client.co.za/premium-engine'
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${API_KEY}`,
},
});
checkForAPIErrors({ response });
const json = await response.json();
return json;
};
Updated 15 days ago