Service Activators

Service activators can be used to do HTTP calls to the backend via pure configuration.

  • Data from the state can be sent to the backend via a mapping configuration
  • Response values from the backend can be written to the state via a mapping configuration
  • Service activators can be executed conditionally
  • Can be used to display server side validations on a page
  • Can be combined with the ngx-xtra dynamic form component to fill possible selections in a dropdown with a server side call.

Service activators can also be triggered via PFE Actions.

Documentation of the configuration

The configuration of service activators is also supported by the config editor:

service activators in editor

1. Types of Service Activators

There are two types of service activators, categorized by their trigger points:

  1. onPageLeaveServiceActivators: These service activators are executed as soon as a forward navigation is triggered. They can be set up in a page configuration under the navConfiguration to perform tasks before leaving the page, such as data validation or data submission.
  2. onPageEnterServiceActivators: These service activators are executed the moment a page is accessed. You can configure them in the firstPage configuration or within a page configuration under the navConfiguration to load the necessary data for preparing the page. Once the data is loaded, it can be used anywhere across the application.

Full details about the execution order can be found here.

💡 If you are looking for a way to trigger HTTP calls during a backward navigation, you can simply use the TRIGGER_SERVICE_ACTIVATORS action in the onPageLeaveBackwardsActions. More details about PFE actions can be found here.

2. Making HTTP Requests

Configuring a service activator to make an HTTP request can be as simple as the snippet below. The configuration triggers a DELETE request when a user navigates away from the summary page.

{
  "pageId": "summary",
  "onPageLeaveServiceActivators": [
    {
      "path": "api/resource/123",
      "serviceActivatorMethod": "DELETE"
    }
  ]
}

3. Connecting HTTP Requests with the PFE State

Often, you would need to incorporate user input into your HTTP request or update the PFE state with the response. This can be done via the requestDataMapping and responseDataMapping.

{
  "pageId": "summary",
  "onPageLeaveServiceActivators": [
    {
      "path": "parties/bank-details",
      "serviceActivatorMethod": "GET",
      "requestDataMapping": [
        {
          // Path to the request payload
          "requestDataExpression": "$.contractId",
          // Path to the state key that contains the desired value
          "stateKeyExpression": "$.selectedPolicy.contractId"
        }
      ],
      "responseDataMapping": [
        {
          // Path to the response payload
          "responseDataExpression": "$",
          // Path in the PFE state to store the response payload
          "stateKeyExpression": "$.customerBankAccounts"
        }
      ]
    }
  ]
}

4. Defining Dynamic Path Parameters

Utilizing dynamic data is not limited to the request payload, it can also be included in a path parameter. PFE allows you to do this by setting up placeholders in the path and providing a mapping between those placeholders and the actual values from the state.

{
  "pageId": "summary",
  "onPageEnterServiceActivators": [
    {
      "path": "parties/{partyId}/bank-details",
      "serviceActivatorMethod": "GET",
      "pathParams": [
        {
          "id": "partyId",
          "value": "$.selectedPolicy.policyHolderId"
        }
      ]
    }
  ]
}

5. Reusing Service Activators

It's a common scenario to use the same service activator multiple times across different parts of your application. Instead of configuring the entire service activator every time, you can define it as a global service activator and then reference it wherever necessary.

{
  "navConfiguration": {
    "serviceActivators": {
      // Define "deleteResource" as a global service activator
      "deleteResource": {
        "path": "api/resource/123",
        "serviceActivatorMethod": "DELETE"
      }
    },
    "pages": [
      {
        "pageId": "summary",
        "onPageLeaveServiceActivators": [
          {
            // Reference it using the "globalConfigId"
            "globalConfigId": "deleteResource"
            // Here you can override or extend the global settings if necessary
          }
        ]
      }
    ]
  }
}

6. Available Options

Beyond the basic setup, PFE offers various options to fine-tune how your service activators operate and interact with the PFE state.

Option Description Default value
path An endpoint or a relative path to the API server URL. This will be prefixed by the serviceActivatorEndpoint, which is a part of the ngxPfeModuleConfiguration configuration. -
responseDataMapping How the response data should be mapped to the state. -
requestDataMapping How the state should be mapped to the request payload. -
serviceActivatorMethod HTTP method, such as GET, POST, PUT or DELETE. POST
pathParams Mapping between path parameters and state keys. -
conditions A list of PFE conditions to decide whether the service activator should be executed. -
globalConfigId Id of a pre-defined service activator to be executed. -
async Whether the service activator should be executed asynchronously. This means, that the loading of a page is not blocked, when the service has not yet returned a result. false
asyncResolveBeforePageIds IDs of pages that should not be rendered until this service activator is finished. -
serviceActivatorResponseStatusHandlers Custom response handling per service activator. -
dontEmitInProgress Don't emit serviceActivatorCallInProgress$. false
cleanStaleState Trigger stale state cleaning. false
updateStateValuesBefore Values in the state that should be updated before sending the HTTP call. -
mapUndefinedResponses Whether to save undefined or null response values to the state. false
errorHandling Error handling configuration. -
displayMessage Short message to communicate what the system is doing. -

7. Error Handling with Service Activators

By default, a failure in a service activator call results in a redirect onto the global error page of the app. A failure is defined as any HTTP error response.

In general, the error handling can be configured in these locations:

  • Directly with the service activator in question
  • Globally. This is the default if no specific configuration is added to a service activator

Error Handling for a Specific Service Activator

The service activator configuration supports the definition of certain errorCases and how they should be handled.

This is done in the errorHandling attribute within the service activator configuration. The configuration itself defines an array of errorCases.

Every ErrorCase handling can define conditions that determine if it should become active or not. The first valid errorCase out of all configured ones is then executed.

The execution of an error case follows these steps:

  1. Run the errorResponseDataMapping configured in the errorCase. This allows it to save data from the payload of the response into the state. It works the same as the responseDataMapping for successful service activators.
  2. Execute the actions that are configured in the errorCase. This makes it possible to handle more specific behavior that is not covered by the standard configuration. The result of the action, directly translates to the behavior of the error handling. If the action returns true, the behavior is the same as with the ignoreError flag. If it returns false, the behavior is the same as with the disableErrorPageNavigation flag. An action can also trigger a custom navigation in this case. Alternatively, it is possible to ignore the action result with the ignoreActionsResult flag.
  3. After this, it is determined if the error should be ignored (ignoreError flag). In this case, no further error handling is done and the service activator behaves the same as a successful one.
  4. If the error was not ignored, it is checked if the error page navigation is disabled (disableErrorPageNavigation flag). For example: If the disableErrorPageNavigation is set for the error case of a service activator, that was triggered in the onPageLeave*, the navigation would be aborted and the user would stay on the current page.
  5. If these flags are not set, the errorPageNavigation of the service activator is used to determine the error page to go to. This navigation works similar to a standard navigation, but is able to access the payload of the error response.
  6. If there is no errorPageNavigation configuration, a fallback to the global error page is done.

A simple example configuration for a service activator with one error case could look like this:

{
  "onPageLeaveServiceActivators": [
    {
      "path": "errorServiceActivator",
      "errorHandling": {
        "errorCases": [
          {
            "conditions": [
              {
                "type": "PFE_EXPRESSION",
                "value1Expression": "$.response.status",
                "operator": "==",
                "value2Expression": "404"
              }
            ],
            "disableErrorPageNavigation": true
          }
        ]
      }
    }
  ]
}

In this example, the service activator runs into a 404 response. It is triggered when the page is left (onPageLeaveServiceActivators) As the disableErrorPageNavigation flag is set, the user will stay on the page and the navigation will be aborted in case of the 404 response.

Conditions of an errorCase

The configuration of the errorCase conditions are the same as the standard navigation conditions. They do however have a few extra gimmicks.

The state is only available under $.state in these conditions. The error response is available under $.response, which means that the response body for error responses is available under $.response.error.

The response headers are available under $.responseHeaders The data model for this can be found here: ErrorCaseConditionsState. They are converted into this structure: [index: string]: string[] The background for this is, that response headers can have duplicates. So the same header could have multiple values.

An example could look like this:

Response headers:

status: 400,
statusText:'error'
error: "Bad Request",
type: "REJECTION",
type: "this is a duplicate value of the type header"
message: "Http failure response for /path: 400 error",

These response headers are then converted to the following data model and provided to the conditions:

{
  "type": ["REJECTION", "this is a duplicate value of the type header"],
  "anotherHeader": ["something"]
}

In this example, we only want the error case to become active, if the type header is set, with the value REJECTION. If this value is not available, the error case should not become active.

This can be done with the following condition/expression:

{
  "value1Expression": "$.responseHeaders.type[?(@==\"REJECTION\")]"
}

This expression checks the values of the type header, if the value REJECTION is present.

To clarify, the following condition would lead to the same result. The extracted valued from the expression is REJECTION. This value is seen as truthy in the conditions.

{
  "value1Expression": "$.responseHeaders.type[?(@==\"REJECTION\")]",
  "operator": "==",
  "value2Expression": "REJECTION"
}

A full example of a service activator call with a more complex error handling of errors could look like this:

{
  "onPageLeaveServiceActivators": [
    {
      "path": "endpoint",
      "errorCases": [
        {
          "conditions": [
            {
              "value1Expression": "$.response.status",
              "operator": "==",
              "value2Expression": "400"
            },
            {
              "value1Expression": "$.responseHeaders.type[?(@==\"REJECTION\")]",
              "operator": "==",
              "value2Expression": "REJECTION"
            }
          ],
          "errorPageNavigation": [
            {
              "nextPageId": "errorPage"
            }
          ]
        },
        {
          "conditions": [
            {
              "value1Expression": "$.response.status",
              "operator": "==",
              "value2Expression": "400"
            }
          ],
          "disableErrorPageNavigation": true
        }
      ]
    }
  ]
}

This example configuration has the effect, that the user will only be navigated to the errorPage if the 400 response also contains the type header with the value REJECTION.

In all other cases, the navigation is stopped and the user stays on the page.

Actions

Actions that run within an error case can also influence the result of the error handling. If one of the actions returns a negative result (false), the error is thrown up. This has the same effect as the disableErrorPageNavigation flag.

errorPageNavigation

An example for a custom errorPageNavigation could look like this:

{
  "onPageLeaveServiceActivators": [
    {
      "path": "endpoint",
      "errorCases": [
        {
          "conditions": [
            {
              "value1Expression": "$.response.status",
              "operator": "==",
              "value2Expression": "500"
            }
          ],
          "errorPageNavigation": [
            {
              "nextPageId": "myCustomErrorPage",
              "conditions": [
                {
                  "value1Expression": "$.response.error.thisServer",
                  "operator": "==",
                  "value2Expression": "isCrashed"
                }
              ]
            },
            {
              "nextPageId": "fallbackErrorPage"
            }
          ]
        }
      ]
    }
  ]
}

The navigation to the myCustomErrorPage only happens if the response body contains the text isCrashed in the field thisServer for the response with the status code 500. If that is not the case, the default fallbackErrorPage is used.

Global Error Page Configuration

The errorPageNavigation configuration can be used to define conditions that determine the error page that should be displayed.

Example for such a configuration:

{
  "navConfiguration": {
    "errorPageNavigation": [
      {
        "nextPageId": "teapotError",
        "conditions": [
          {
            "value1Expression": "$.response.status",
            "operator": "===",
            "value2Expression": "418"
          }
        ]
      },
      {
        "nextPageId": "defaultErrorPage"
      }
    ]
  }
}

The conditions to determine if a navigation to an error page should happen are similar to the NavOptionConfig conditions. But in difference to those, the PFE state is only available under $.state in the error page navigation conditions.

Additionally the response data is available:

  • The error response is available under $.response
  • The http status is available under $.response.status
  • The response body for error responses is available under $.response.error
  • The response headers under $.responseHeaders

The errorResponseDataMapping in the errorCases configuration of a specific service activator can be used to write the error response data to the state before the error page navigation is triggered.

Example for a Service Activator for a Validation

The user will only be able to navigate, once the service returned a non-error response

{
  "path": "some-service/validate",
  "serviceActivatorMethod": "POST",
  "preventNavigationOnError": true,
  "requestDataMapping": [
    {
      "requestDataExpression": "$.fieldToValidate",
      "stateKeyExpression": "$.userdata.fieldToValidate"
    },
    {
      "requestDataExpression": "$.anotherFieldToValidate",
      "stateKeyExpression": "$.userdata.anotherFieldToValidate"
    }
  ],
  "responseDataMapping": [
    {
      "responseDataExpression": "$",
      "stateKeyExpression": "$.someService.validationStatus"
    }
  ],
  "serviceActivatorErrorHandlingExcludeStatusCodes": [404, 400],
  "serviceActivatorResponseStatusHandlers": [
    {
      "statusCode": 400,
      "stateKeyExpression": "$.validationErrorData",
      "stateValue": "common.validation.formatError"
    },
    {
      "statusCode": 404,
      "stateKeyExpression": "$.validationErrorData",
      "stateValue": "common.validation.notFoundError"
    }
  ]
}

8. Trigger Service Activators Through Code

While it is recommended to rely on the trigger points of the navigation flow, it is also possible to trigger service activators directly in the code. The PfeBusinessService provides the triggerSingleServiceActivator() for this.

It can be used like this:

this.pfeBusinessService
  .triggerSingleServiceActivator('serviceActivatorID')
  .then((response) => {
    // The full HTTP response of the service activator is available here
  })
  .catch((error) => {
    // The full HTTP error response of the service activator is available here
  });

By default, the PFE error handling is active for every service activator. That means an automatic navigation to the error page is triggered.

It might be desirable to stay on the current page, for example if the error is supposed to be handled manually in the code of the catch block. This can be done, by disabling the navigation to the error page for the service activator in question. For example:

{
  "errorServiceActivator": {
    "path": "http://example.com/this-is-a-404",
    "serviceActivatorMethod": "GET",
    "errorHandling": {
      "errorCases": [
        {
          "disableErrorPageNavigation": true
        }
      ]
    }
  }
}

results matching ""

    No results matching ""