Orchestration Components
Here are the main features of a DX Component:
- May or may not use a Connection
- Can retrieve data directly from the backend system via the Connection or from other Orchestration Components
- Can be passed a real-time Context, which may be received from the client application or set by one of the other Orchestration Components
- May or may not process business rules to drive aspects of the business logic based on the Context passed to it
- Can cache it's response to avoid unnecessarily calling backend APIs or process information that has already been processed
- Can manipulate and transform data received from various inputs
- Can be chained with other Orchestration Components
Note: Orchestration Components are NOT the same as UI Components. They may provide the data that can be consumed by the UI Component, but do not provide any HTML/CSS or any other framework specific code/markup.
Creating a Component
- Navigate to Manage Experiences > Experience Component.
- Click the “+ Add Component” button to create a new Component.
- In the form modal, enter the following information:
- Component Code: This is a unique name for the Component.
- Component Name: A friendly name for the Component.
- Component Description: A description of what the Component does
- Logo: The URL to a logo to be associated with the Component (will default if left empty).
- Is Asynchronous: If checked, this Component will be executed asynchronously and the DX Engine response will not wait for it to complete. If this Component is depended upon by any synchronous Component, this Component will be executed synchronously.
- No Rules: Check this box if Component will have no Experience Rules associated with it.
- In the Component Type field, select the type of Component you want to create.
- Click Submit.
After you have saved this initial set up, the new Component will be added to the Component listing. Click the Component's Edit button to complete configuration.
Component Naming Conventions
Since Components make an API call which perform a CRUD operation, it is good to have a descriptive name - <Action performed> <Resource/noun> <SaaS used(optional)>
. For example:
Get Cart ID
Get Hero Banner - Cloudinary
Remove Items from Cart
If you use any mapper, data transformation script, or metadata Components, you can prefix the Component with Model
, Mapper
, Metadata
, Transform
, etc to give a clear indication that this Component performs data manipulation. For example:
Mapper - Hero Banner - Cloudinary
Model - Featured Products
Component Configurations
All Orchestration Components have some sort of configuration that controls the Component's behaviour. Some behaviours include:
- Select the content type in which to fetch specific content records
- Determine the search index to query
- Choose a promotion to offer
- Specify a value to transform
- Select a collection to write to
- Provide a list of products to remove from inventory
- Determine whether the Component should do anything at all
To Configure a Component:
- Find the Component in the listing.
- Click on Component's Edit button.
Many configurations can use values that are determined at query-time via Expressions.
There are three different methods of specifying configuration values:
Method | Description |
---|---|
Literal | A hardcoded configuration value is specified within the Component at setup-time. |
Context Field | The configuration value is determined at query-time by using the value from the specified Context Field. |
JS Expression | The configuration value is determined at query-time by evaluating an expression (which has access to all Context Fields and Component results) |
There are a common set of configurations that all DX Engine Components have. Depending on the type of Component, there are configurations that are specific to a Component.
Common Configurations
Name | API Property | Uses Expressions | Description |
---|---|---|---|
Context Field Enrichments | contextFieldEnrichment | Yes | Uses the Component's response to calculate values to be put into the Context for other Orchestration Components to reference. See details here. |
Sub Components | subComponents | Yes | Provides a way to enrich each record in a Component's response with the results of other Component executions using custom Contexts. See details here. |
Cached | cacheConfig.cached | No | If set to true , the responses of this Component will be cached. The default value is false . |
Cache Time-to-live | cacheConfig.cacheTtl | No | The number of seconds that cached responses will be cached. |
Cache Tag Configuration | cacheConfig.cacheTags | No | A list of tags that will be associated with the cached response. See details here |
Trigger Expression | trigger | Yes | The default value is true . |
Validity Expression | validity | Yes | The default value is true . |
Skip on Failed Dependency | skipOnFailedDependency | No | The Component's execution is skipped if any of the Components on which it depends, is in a FAILED state. |
Skip on Skipped Dependency | skipOnSkippedDependency | No | The Component's execution is skipped if any of the Components on which it depends, is in a SKIPPED state. |
Skip on Invalid Dependency | skipOnInvalidDependency | No | The Component's execution is skipped if any of the Components on which it depends, is in an INVALID state. |
Metadata | metadata | No | Key/value pairs with additional metadata to include on this Component. |
Response Transform | responseTransform | Yes | Modifies (or completely overwrites) the Component's response. |
The API Property is the corresponding property to update via the Management API.
Component-Specific Configuration
Component-specific configurations are dependent upon the specific Component Type. The available configurations for each Component are documented on that Component's documentation page.
See Configuring Components for more information.
Expressions
Expressions allow for query-time evaluation of values using JavaScript syntax. Example: response.customerSegment
and componentResponse('myComponent')
.
Depending on where an expression is used, it has access to different set of variables/functions.
All expressions have access to the following Javascript variables/functions:
Variable/Function | Description |
---|---|
_ | Lodash utility |
encodeURI | Native Javascript function |
encodeURIComponent | Native Javascript function |
JSON | Native Javascript Object |
Array | Native Javascript Object |
Promise | Native Javascript Object |
Object | Native Javascript Object |
DateTime | Date and Time manipulation utility from the luxon library |
Expressions used for Component-specific query parameters
When a new Component Type is created such as commercetools Dynamic Record List or Contentful Static Record List, specific parameters are made available to query these backends. For instance, a dynamic record list for commercetools requires Category ID to be passed to commercetools. You can also pass values such as Sort, Filter, etc.
Variable/Function | Description | Example |
---|---|---|
contextField(contextField) | Pass a value from the Context Field as a Query Parameter. | contextField('categoryID') |
componentResponse(componentCode) | Pass a value from an upstream Component response as a Query Parameter | ``_.castArray(componentResponse('fetchProductIDs').productIDs)` |
componentStatus(componentCode) | Check to see if an upstream Component was processed successfully | componentStatus('fetchProductIDs') |
Expressions used for Triggers
These expressions are evaluated to determine whether the current Component should be processed. The expression is expected to return a boolean value (true or false). However, if it returns a non-boolean value, the DX Engine will determine the Component's processing based on the 'truthiness' or 'falsiness' of that value. In JavaScript, certain values are inherently falsy (e.g., false, 0, "" (empty string), null, undefined, NaN), while all other values are considered truthy. This behavior allows for flexible expression evaluations in determining the processing logic of the Component.
Variable/Function | Description | Example |
---|---|---|
contextField(contextField) | Fetch the value of the Context Field by Name | contextField('location')==='US' |
componentResponse(componentCode) | Fetch the response of an upstream Component | _.castArray(componentResponse('fetchProductIDs').productIDs).length > 0 |
componentStatus(componentCode) | Check the status of an upstream Component | componentStatus('callCustomerDatabase')==='VALID' |
Expressions used for Validity
These expressions check for the Validity of the response of the Component currently being processed. The expression is expected to return a boolean value (true or false). However, if it returns a non-boolean value, the DX Engine will determine the response validity on the 'truthiness' or 'falsiness' of the resulting value. In JavaScript, certain values are inherently falsy (e.g., false, 0, "" (empty string), null, undefined, NaN), while all other values are considered truthy.
Variable/Function |
---|
response |
contextField(contextField) |
componentResponse(componentCode) |
componentStatus(componentCode) |
Expressions used for Context Field Enrichments
Context Fields are available to all Components that are to be processed within the scope of a single Experience API call. Each Component has the ability to update the Context of the query and all downstream Components will always read the most up to date value of the Context.
Variable/Function | Description | Example |
---|---|---|
response | Response of the current Component being processed | response.customerSegment |
contextField(contextField) | Fetch the value of the Context Field by Name | contextField('categoryID') |
Expressions used for Sub Components
Variable/Function |
---|
response |
Component X becomes dependent upon Component Y when Component X uses any expression (anywhere within Component X's configurations) that contains:
- Uses
contextField('someContextField')
wheresomeContextField
is enriched by Component Y's Component Field Enrichments - Uses
componentResponse('componentB')
- Uses
componentStatus('componentB')
Component Statuses
When a query is made to the DX Engine Experience API, all of the requested Components are processed. The following flowchart describes the various states that a Component goes through.
State | Description |
---|---|
PROCESSING | A request to the DX Engine has occurred and this Component is part of fulfilling the reponse. Uses the Trigger expression to determine if it should run. If so, the Component is executed (enters the EXECUTING state). Otherwise, this Component will not be executed (enters SKIPPED state). |
WAITING_FOR_COMPONENT_DEPENDENCIES | Waits for any Orchestration Components on which it depends to be complete (either of the following states: VALID , FAILED , SKIPPED ). Afterwards, the engine determines if the Component should be skipped. It will be skipped if any of the Skip on xxx Dependency (see this) checks are satisfied. Otherwise, the Component is executed (enters the EXECUTING state) |
EXECUTING | The Component logic is run. If any failure occurs during the execution, it enters FAILED state. Otherwise, the Component enters VALID state. If a Validity expression was specified, it is evaluated. If it evaluates to false , the state moves to INVALID . |
SKIPPED | The Component was not executed. |
VALID | The Component's response is valid. |
INVALID | The Component's response is not valid. |
Component Metadata
Metadata are key/value pairs that you define on Components. The metadata values are not part of the main Component response, but rather found in the Component @extras section where triggered Experience Rule data also lives.
{
"example-component": {
"@extras": {
"rule": {
"metadata": [],
"attributes": {}
},
"metadata": [
{
"key": "__typename",
"value": "Banner"
},
{
"key": "sort_order",
"value": "6"
}
]
},
"status": "VALID",
"response": {}
}
}
You can access a Component's metadata using the following expressions:
._get(componentExtras('example-component'), 'metadata')
componentExtras('example-component').metadata
componentExtras('example-component').metadata.filter(entry => entry.key === '__typename')
Orchestration
With Expressions and Component Statuses, the DX Engine allows for many complex real-time orchestration scenarios.
Context Field Enrichment
After a Component is executed and it is valid, it will process its Content Enrichments (if any). Take the following Context Field Enrichment configuration.
After this Component is run and gets a response from whatever data source it is querying, it will evaluate each of the three expressions and put the value into the request's context so that other Orchestration Components can use it. If a Context Field already exists, its value will be overwritten.
If Component A references a Context Field that is enriched (via Context Field Enrichment) by Component B, then the DX Engine is aware that Component A depends on Component B and will ensure that:
- Component B is executed, even if it was not explicitly requested by the DX Engine Query.
- Component B is executed BEFORE Component A is executed.
Sub Components
After a Component is executed and it is valid, it will process its Sub Components (if any). Take the following Sub Component configuration on a given parent Component.
After the parent Component is run, it will:
- If specified, modify the parent Component Response by evaluating the Response Transformation Expression.
- Create a new Context that is a copy of the context available to the current Component with the addition of a new Context Field,
actorIds
. Note: This newly-created Context is only available to the specified Orchestration Components in the Sub Components configuration (actors
). - Execute the the
actors
Component. - Add the response of the
actors
Component into the parent Component's response under the property,movieActors
.
Sub Components will always be executed synchronously, even if they were configured to be asynchronous.This is because the results of the Sub Components are written back to the parent Component's (the Component that executed the Sub Components) response so the parent Component must wait for the Sub Components to complete.
When a Component has Sub Components, its response must be either an object or an array of objects. That is because each Sub Component's response will be "inserted" into the parent Component's response using a specified Property Name
.
If the response of a Sub Component is an array, then any configured Sub Components will be executed once for each item in the array. Otherwise, if the parent Component's response is an object, the Sub Components will be executed once.
The Context Field Expression is a JavaScript expression that has access to a variable called response
, which refers to the response of parent Component, or each item in the parent Component's response if that response is an array.
The Orchestration Components specified within another Component's Sub Component configuration may, themselves, have more Sub Components. There is no limit to this nesting. This "nested orchestration" is much like the possible nesting seen with GraphQL (but without the need to write resolver code!).
Display Templates
When records are displayed as part of an experience rule (or as part of a data grid in DX Graph), the look and feel of each record is controlled by the "display template". The display template is a snippet of HTML code that can contain elements of data combined with visual styling to make the record listing more visually friend to the business user.
In the example above, the display template is defined to show elements of the record including the image, name and description.
Defining a Display Template
For 'Static' Components, you can configure a 'Display Template' to control the business user's editing experience. Here is how it's done:
- Navigate to the Components dashboard.
- Find the experience Component of interest.
- Click the Edit button.
- Under the "Options" portion of the Component, find the "Display Template" section.
- Click on the code view("< >") button to bring up the HTML editor.
- Define the display template. Here, you can include HTML as well as attributes of the record using the
{{myAttribute}}
syntax. - Once done, click the code view button again to visualize the record look and feel.
- Save the Component
In the example above, title, description and other attributes are defined as part of the display template. The actual name of the attribute will vary based on your collections schema mode. In most cases, the field code of the attribute can be used. If your target field is a nested field in the schema, simply define the path like in the example above.
Once the display template has been defined and saved, navigate back to the corresponding experience rule to see the updated look and feel of the records.
Sample Display Template
The following display template HTML generates the layout seen in the record list above with an image to the left and name and description to the right.
<div style="display:inline;text-align:left;">
<div style="display:inline;text-align:left;margin-right:20px;"><img src="{{Image_URL}}" height="75px" class="fr-fic fr-dii"></div>
<div style="vertical-align:top;display:inline-block;">
<div style="font-weight:600;font-size:1.5rem;margin-bottom:10px;">{{Name}}</div>
<div style="font-weight:400;font-size:1.2rem;margin-bottom:10px;">{{Header}}</div>
</div>
</div>
The DX Engine gives business users the ability to define what content should be seen by who, when and where. However, sometimes, you want to pass additional information to the calling application beyond the content or data fetched from external systems. Also, you want these options to be presented to the business user in an intuitive visual editor.
Using Component Attributes as Front-end Design Props
To empower digital teams to pass along additional information and directions to the frontend, the DX Engine offers Component Level Attributes. One of the use cases for Component Level Attributes is Design Props that the frontend could use to render itself. An example of this would be how you want the layout to be adjusted based on the context of the user. Or, it could be the styling that should be applied to the visual Component.
As an example, we have a Component that returns the hero banner. A business user may want to personalize the experience and show a full width banner in some cases but a split banner in other cases. This can be configured as an attribute. In this example, we'll call our attribute "layout" and setup the option for the user to select between "full width" and "split".
Setting Up Component Attributes
- Navigate to the Components dashboard.
- Find the experience Component of interest (in our case a hero banner Component) and click Edit.
- In the tab selector (top right), select the "Attribute Definition" tab.
- Create a new attribute by clicking on the "Add another item" button.
- For the attribute, give it a property, name and description. In our case, ours will be called "layout".
- Under the configuration, select "List".
- In the List of Values area, this is where you can define the options the user will be able to select from as well as the properties of each option. We'll define an option for
boxed
,fullwidth
andsplit
(side by side). For each, we'll give it a display name, image and description. These will be used in the next step.. - In the Template part of the configuration, we can define how the defined options will show up visually. Here we'll define an HTML snippet that shows an image and name for each option.
- Save the Component.
Selecting an Attribute Option
Once the attribute definition(s) are setup, they automatically appear in the Experience Rule as part of the target experience section. Here you can see the options we setup.
Using the Attributes
In the Component response, attributes are returned as part of the @extras
section. This can be used by the front-end to drive additional behaviour related to the attribute.
._get(componentExtras('cloudinary-hero-banner'), 'rule.attributes')
Types of Attributes
In order to provide user friendly editor experience for non-technical users, the DX Engine offers several types of Attributes:
Name | Description |
---|---|
Text | Prompts the user to enter some text value. There is formatting for: JavaScript , JSON , Handlebars , Markdown , HTML |
Number | Prompts the user to enter a numeric value. |
Checkbox | Prompts the user to check or uncheck a checkbox. This satisfies Yes/No ; On/Off |
Manual Picklist | Prompts the user to pick a value from a dropdown. The available values are manually-provided during the configuration of a Component. |
Component Response Picklist | Prompts the user to pick a value from a dropdown. The available values are dynamically fetched from some other source using another Component. This allows you to fetch values, for example, another webservice or a delimited file from an S3 bucket. |
Manual List | Prompts the user to re-order a list of values. The available values are manually-provided during the configuration of a Component |
Component Response List | Prompts the user to re-order a list of values. The available values are dynamically fetched from some other source using another Component. |
Common Component Attribute Configurations
Each Attribute has the following common configurations:
Name | Property | Description |
---|---|---|
Attribute Property | attributeProperty | The name of the property in the Component's JSON response that will store the value of the Attribute. |
Attribute Name | attributeName | The display name of the Attribute when displayed to the business user. |
Attribute Description | attributeDescription | The description of the Attribute when displayed to the business user. |
Attribute Required | attributeRequired | Whether the Attribute is required or optional. |
Attribute Type | valueConfig.type | How the value of the Attribute should be collected from the business user. |
Component Attribute Configurations based on Attribute Type
Depending on the Attribute Type, the Attribute may have additional configurations.
Name | Property | Description |
---|---|---|
Default Text Value | defaultTextValue | The default value of the Attribute when the business user is setting up rules for a Component. This is only valid when Value Type is Text . |
Default Number Value | defaultNumberValue | The default value of the Attribute when the business user is setting up rules for a Component. This is only valid when Value Type is Number . |
Default Checkbox Value | defaultCheckboxValue | The default value of the Attribute when the business user is setting up rules for a Component. This is only valid when Value Type is Checkbox . |
List of Values | valueConfig.list | A hardcoded list of available values for the Attribute. The specified value is a JSON array of objects where each object must have a property called value . The value property is used to store the value of the Attribute. Each object may any other number of properties. These properties are used to display the available values to the business user in the UI using a Display Template. This is only valid when Value Type is Manual Pick List or Manual List . |
Component Code | valueConfig.componentCode | The code of the Component that will be used to retrieve the available values for the Attribute. This is only valid when Value Type is Component Response Pick List or Component Response List . |
Display Template | valueConfig.displayTemplate | A Handlebars HTML template used to display the available values to the business user in the UI. This is only valid when Value Type is Manual Pick List , Manual List , Component Response Pick List or Component Response List . |
When hardcoding a list of available values for an Attribute (e.g. when the Value Type is Manual Pick List
or Manual List
), the specified value is a JSON array of objects where each object must have a property called value
. The value
property is used to store the value of the Attribute. Each object may have any other number of properties. These properties are used to display the available values to the business user in the UI using a Display Template. The Display Template is specified as a Handlebars HTML template.
When retrieving a list of available values for an Attribute from another Component (e.g. when the Value Type is Component Response Pick List
or Component Response List
), the Component Code of the Component that will be used to retrieve the available values must be specified. The result of the Component must be in the format described in List of Values
. The Display Template is specified as a Handlebars HTML template.
Example of List of Values
[
{
"value": "layout01",
"name": "Layout One",
"logoUrl": "https://images.com/layout-01.png"
},
{
"value": "layout02",
"name": "Layout Two",
"logoUrl": "https://images.com/layout-02.png"
},
{
"value": "layout03",
"name": "Layout Three",
"logoUrl": "https://images.com/layout-03.png"
},
{
"value": "layout04",
"name": "Layout Four",
"logoUrl": "https://images.com/layout-04.png"
}
]