File

libs/ngx-pfe/pfe-service-activator/service/service-activator.model.ts

Description

Configuration for the HTTP response status used by the service activators. Allows to write to the state custom messages depending of the configured HTTP status codes. If the response code is a match a value will be written to the state.

Index

Properties

Properties

stateKeyExpression
stateKeyExpression: JsonPathExpression
Type : JsonPathExpression

The key specified in stateValue property will be written in this path.

stateValue
stateValue: string
Type : string

Writes the string passed here to the state in case that the response HTTP status code is a match.

statusCode
statusCode: number
Type : number

The HTTP response code expected that triggers this config.

import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { JsonPathExpression } from '../../models/jsonpath-expression-type.model';
import { ConditionAdvancedE, ConditionE, NavOptionErrorPageConfig } from '../../models/navigation-config-error-page.model';
import { StateUpdates } from '../../models/navigation-config.model';
import { PfeUserInputState } from '../../models/pfe-state/user-input-state.model';
import { UnknownObject } from '../../models/unknown-object.model';
import { PfeActionConfig } from '../../pfe-actions/pfe-actions.model';
import { Conditions, ExpressionCondition } from '../../pfe-conditions/public-api';
import { HTTPResponseHeaders } from '../../util/convert-http-response-headers';

export interface HttpParamsOptionsFromObject {
  [key: string]: string | string[];
}

export enum ServiceActivatorHTTPMethods {
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
}

export interface ExtendedDisplayMessage {
  headline: string;
  subline?: string;
}

export type ServiceActivatorProgressDetails = Omit<NavServiceActivatorConfig, 'displayMessage'> & {
  displayMessage?: ExtendedDisplayMessage;
};

/**
 * Configuration for the HTTP response status used by the service activators.
 * Allows to write to the state custom messages depending of the configured
 * HTTP status codes. If the response code is a match a value will be written
 * to the state.
 */
export interface ServiceActivatorResponseStatusHandler {
  /**
   * The HTTP response code expected that triggers this config.
   */
  statusCode: number;
  /**
   * The key specified in `stateValue` property will be written in this path.
   */
  stateKeyExpression: JsonPathExpression;
  /**
   * Writes the string passed here to the state in case that the response
   * HTTP status code is a match.
   */
  stateValue: string;
}

/**
 * Configuration for a service activator to be called.
 */
export interface NavServiceActivatorConfig<ACTIONS = PfeActionConfig> extends LegacyErrorHandlingConfig {
  /**
   *
   * @deprecated true
   * @deprecationMessage Will throw an error if used. Please use `globalConfigId` instead.
   */
  globalConfigID?: string;
  /**
   * Optional id of a service activator in the global config.
   *
   * If a service activator with this id is found in the global config, it is used.
   *
   * If there are additional attributes defined in this configuration, those will partially override
   * the global configuration.
   */
  globalConfigId?: string;

  /**
   * Short message to communicate what the system is doing. You can pass an object with
   * the keys `headline` (mandatory) and `subline` (optional). Alternatively, you can directly pass a string,
   * which sets the `headline` of the spinner implicitly.
   */
  displayMessage?: string | ExtendedDisplayMessage;

  /**
   * The path of the service activator.
   * This is defined by the BFF API.
   */
  path?: string;

  /**
   * Path params that appear in the path
   * With this we are going to be able to build the complete url<br>
   * <b>Example</b>: If we want to make a call to <i>https://endpoint.com/contract/1</i>
   * where that '1' is a value from the app then we should:<br>
   *  - Define path as endpoint/contract/{appValueId} <b>IMPORTANT</b>: No spaces in the dynamic content. <br>
   *  - Define pathParams as: <br>
   *   [
   *     { <br>
   *       id: 'appValueId', <br>
   *       value: jsonExpression <br>
   *     }
   *   ]<br> being jsonExpression, the expression to get from state the value.
   */
  pathParams?: PathParams[];

  /**
   * Defines the HTTP call method. Use: POST, GET or PUT.
   */
  serviceActivatorMethod?: ServiceActivatorHTTPMethods;

  /**
   * Defines the conditions to make the ServiceActivator call to the back-end.
   * As it is an Array, you can define more then one condition and all of them
   * must be TRUE to make the ServiceActivator call.
   * (in short: it's an "AND" condition, not an "OR").
   *
   * Example:
   *
   * conditions: [
   *       {
   *         value1Expression: '$.food',
   *         operator: '==',
   *         value2Expression: 'schnitzel'
   *       },
   *       {
   *         value1Expression: '$.price',
   *         operator: '>',
   *         value2Expression: '1'
   *       }
   *     ]
   */
  conditions?: Conditions;

  /**
   * Defines, how the state should be mapped to the request payload.
   * This enables you to transform the state objects into anything you would like to send to the back-end API.
   *
   * Example, if you have your state modeled like this:
   *
   * {
   *  "user": {
   *     "name": "Michael"
   *     "age": "33"
   *   },
   *  "familyInformation": {
   *    "children": 1,
   *    "married": yes,
   *   }
   *  "sensitiveInformation": {
   *    "password": "1234",
   *    "creditcard": "1234-1234-1234-1234",
   *   }
   * };
   *
   * You probably want to avoid sending the "sensitiveInformation" object to the back-end,
   * and for this example, lets glue the "user" and "familyInformation" objects into just one
   * object called "userInfo" to show how we can manipulate/extend objects.
   *
   * Your requestDataMapping configuration has to be like this:
   *
   * {
   *  requestDataMapping: [{
   *     stateKeyExpression: '$.user',
   *     requestDataExpression: '$.userInfo'
   *  }, {
   *     stateKeyExpression: '$.familyInformation',
   *     requestDataExpression: '$.userInfo'
   *  }]
   * }
   *
   * Then the back-end API will receive this object:
   *
   * {
   *  "userInfo": {
   *     "name": "Michael"
   *     "age": "33"
   *     "children": 1,
   *     "married": yes,
   *   }
   * };
   */
  requestDataMapping?: ServiceActivatorDataMappingForRequesting[];

  /**
   * Defines, how the response data should be mapped to the state.
   */
  responseDataMapping?: ServiceActivatorDataMapping[];

  /**
   * Execute the service activator call asynchronously.
   * This means, that the loading of a page is not blocked, when
   * the service has not yet returned a result.
   * Should not be set for the following page in the navigation.
   * In this case, a service activator should just be executed synchronously
   * Default: false
   */
  async?: boolean;

  /**
   * Ensures, that an asynchronous service activator call finishes successfully
   * (i.e., "is resolved") before one of the pages with one of the "pageIDs" is shown.
   * If the call has not yet returned, the display of the page will be delayed until
   * it is returned.
   *
   * If the same call is performed several times, it is considered as "resolved" as long
   * as the latest call was successful. Therefore, a retry mechanism for unsuccessful
   * calls could eventually mark the call as "resolved".
   */
  asyncResolveBeforePageIds?: string[];

  /**
   * Custom response handling per service activator. See ServiceActivatorResponseStatusHandler interface.
   */
  serviceActivatorResponseStatusHandlers?: ServiceActivatorResponseStatusHandler[];

  /**
   * If set to "true", the SA don't emit `serviceActivatorCallInProgress$` in that way you can make a call
   * in your app and don't show the page loader (a.k.a LottieAnimations)
   * If you want to trigger only before a page you can have a GlobalServiceActivator and then in the cfg
   * ```json
   *  {
   *      "globalConfigId": "myServiceActivator",
   *      "dontEmitInProgress": true
   *  }
   * ```
   * If a pages have more than 1 OnEnter / OnLeave service activator and only one of them emit the event
   * all emit the event.
   */
  dontEmitInProgress?: boolean;

  /**
   * set to true to trigger stale state cleaning
   * this is optional because it can be overriden by the pfeConfig "autoCleanState"
   */
  cleanStaleState?: boolean;

  /**
   * List of possible userInputState updates
   * To be executed before doing the service activator call
   */
  updateStateValuesBefore?: StateUpdates[];

  /**
   * Boolean to enable undefined responses to be mapped to the state
   */
  mapUndefinedResponses?: boolean;

  /**
   * Contains the error handling configuration for this service activator.
   *
   * If no configuration is given, the default behavior of going to the global error page is active.
   *
   * If a configuration is given, it will be activated in case of error responses.
   */
  errorHandling?: ServiceActivatorErrorHandlingConfig<ACTIONS>;
}

/**
 * Internal NavServiceActivatorConfig, that is not published in the json-schema
 */
export interface NavServiceActivatorConfigInternally<ACTIONS = PfeActionConfig> extends NavServiceActivatorConfig<ACTIONS> {
  /**
   * Flag to remember, if this service activator config was already spread with the global one.
   */
  _alreadySpread?: boolean;

  /**
   * Service activators that are run during the startup of the application cannot
   * use the standard error handling, as the navigation is not fully ready yet.
   *
   * This flag is used to prevent the error navigation in that case.
   * Everything else in the service activator error handling is done as usual. (For example the mapping)
   */
  _disableErrorPageNavigation?: boolean;
}

/**
 * The service activator configs.
 */
export type NavServiceActivatorConfigsArray<ACTIONS = PfeActionConfig> = NavServiceActivatorConfig<ACTIONS>[];

export interface ServiceActivatorDataMapping {
  /**
   * The jsonpath expression, where the retrieved data should
   * be stored in the state.
   *
   * It is possible, to access deeply nested structures in this expression.
   * Parts to the structure, that do not yet exist, are automatically created.
   *
   * If $ is used as expression, a spread of the responseData on the state is done
   */
  stateKeyExpression: JsonPathExpression;

  /**
   * Jsonpath expression to extract data from the retrieved service
   * activator response.
   */
  responseDataExpression: JsonPathExpression;

  /**
   * Use the http response instead of the body as source for
   * the responseDataExpression.
   * Allows access to the HttpResponse @link{https://angular.io/api/common/http/HttpResponse}
   * which also contains the http headers and status code.
   *
   * Example Expressions:
   * Get the HTTP Status:
   * ```
   * $.status
   * ```
   *
   * Access the response body of a successful call:
   * ```
   * $.body
   * ```
   *
   * Access the response body in an error case:
   * ```
   * $.error
   * ```
   */
  useHTTPResponseAsData?: boolean;

  /**
   * # ExpressionCondition Syntax
   *
   * The conditions use jsonPath (https://github.com/dchester/jsonpath) expressions to select data from the state.
   * There is tooling support available to create and test jsonpath expression.
   * The PFE dev tools also contain a possibility to test and debug expressions against a JSON.
   *
   * The conditions to be evaluated can either be an array of {@link ExpressionCondition} or an {@link ConditionAdvanced} object.
   *
   * They are an optional attribute. If they are omitted, the result of true is assumed.
   *
   * The selected data can then be compared with certain operators to a second value or a literal.
   *
   * Possible operators are
   *
   * ```
   * ==
   * ```
   * Checks if the two values are equal.
   *
   * ```
   * !=
   * ```
   * Checks that the two values are not equal.
   *
   * ```
   * < and >
   * ```
   * Compares the numerical value, to check if one of them is larger or
   * smaller than the other one.
   *
   * The jsonpath syntax has the following basic format:
   *
   * ```
   *  $.<attribute or expression>
   * ```
   *
   * For example:
   *
   * ```
   *  $.myCustomTextAreaID
   * ```
   *
   * Keys, that contain special characters can be accessed in the following way:
   *
   * ```
   *  $['some-attribute-name']
   * ```
   *
   * Example configuration.
   *
   *
   * ```json
   *  "responseDataMapping": [
        {
          "responseDataExpression": "$.response",
          "stateKeyExpression": "$.response.localObject",
          "conditions": [{
            "expression": "{$.booleanValueInTheState}"
          }]
        },
   * ```
   */
  conditions?: ExpressionCondition[];
}

export interface ServiceActivatorDataMappingForRequesting {
  /**
   * The local state object to get mapped into the request.
   * this is the "FROM" part of the Mapping
   * (From the State > To the Request)
   */
  stateKeyExpression: JsonPathExpression;

  /**
   * How to be addressed into the request.
   * This is the "TO" part of the Mapping
   * (From the State > To the Request)
   */
  requestDataExpression: JsonPathExpression;

  /**
   * # ExpressionCondition Syntax
   *
   * The conditions use jsonPath (https://github.com/dchester/jsonpath) expressions to select data from the state.
   * There is tooling support available to create and test jsonpath expression.
   * The PFE dev tools also contain a possibility to test and debug expressions against a JSON.
   *
   * The conditions to be evaluated can either be an array of {@link ExpressionCondition} or an {@link ConditionAdvanced} object.
   *
   * They are an optional attribute. If they are omitted, the result of true is assumed.
   *
   * The selected data can then be compared with certain operators to a second value or a literal.
   *
   * Possible operators are
   *
   * ```
   * ==
   * ```
   * Checks if the two values are equal.
   *
   * ```
   * !=
   * ```
   * Checks that the two values are not equal.
   *
   * ```
   * < and >
   * ```
   * Compares the numerical value, to check if one of them is larger or
   * smaller than the other one.
   *
   * The jsonpath syntax has the following basic format:
   *
   * ```
   *  $.<attribute or expression>
   * ```
   *
   * For example:
   *
   * ```
   *  $.myCustomTextAreaID
   * ```
   *
   * Keys, that contain special characters can be accessed in the following way:
   *
   * ```
   *  $['some-attribute-name']
   * ```
   *
   * Example configuration.
   *
   *
   * ```json
   * "requestDataMapping": [
        {
          "requestDataExpression": "$.licenseplate",
          "stateKeyExpression": "$.userdata.insuredProperty.licensePlate",
          "conditions": [{
            "expression": "{$.booleanValueInTheState}"
          }]
        }
      ]
   * ```
   */
  conditions?: Conditions;
}

export interface PathParams {
  /**
   * Id of the param that matches with the one in
   * that is part of the path.
   */
  id: string;
  /**
   * The jsonpath expression, where the retrieved data should
   * be retrieved from the state.
   */
  value: JsonPathExpression;
  /**
   * # ExpressionCondition Syntax
   *
   * The conditions use jsonPath (https://github.com/dchester/jsonpath) expressions to select data from the state.
   * There is tooling support available to create and test jsonpath expression.
   * The PFE dev tools also contain a possibility to test and debug expressions against a JSON.
   *
   * The conditions to be evaluated can either be an array of {@link ExpressionCondition} or an {@link ConditionAdvanced} object.
   *
   * They are an optional attribute. If they are omitted, the result of true is assumed.
   *
   * The selected data can then be compared with certain operators to a second value or a literal.
   *
   * Possible operators are
   *
   * ```
   * ==
   * ```
   * Checks if the two values are equal.
   *
   * ```
   * !=
   * ```
   * Checks that the two values are not equal.
   *
   * ```
   * < and >
   * ```
   * Compares the numerical value, to check if one of them is larger or
   * smaller than the other one.
   *
   * The jsonpath syntax has the following basic format:
   *
   * ```
   *  $.<attribute or expression>
   * ```
   *
   * For example:
   *
   * ```
   *  $.myCustomTextAreaID
   * ```
   *
   * Keys, that contain special characters can be accessed in the following way:
   *
   * ```
   *  $['some-attribute-name']
   * ```
   *
   * Example configuration.
   *
   *
   * ```json
   * "pathParams": [
        {
          "id": "myParam",
          "value": "$.some.state.value",
          "conditions": [{
            "expression": "{$.booleanValueInTheState}"
          }]
        }
      ]
   * ```
   */
  conditions?: Conditions;
}

export interface ServiceActivatorErrorHandlingConfig<ACTIONS> {
  /**
   * An error case configuration contains the handling of a specific error response.
   *
   * The configured conditions decide if an error case becomes active.
   *
   * Once it is active, all other cases are ignored. The cases are checked in the configured order.
   *
   * An error case can then contain a specific handling of an error, with actions, a data mapping and the decision
   * what should happen in the navigation.
   *
   * If only some errors should be handled and all others should be ignored, it is possible to add
   * a case at the end of the list, that simply matches all errors and ignores them.
   */
  errorCases: ErrorCase<ACTIONS>[];
}

/**
 * Used in {@link ServiceActivatorErrorHandlingConfig#errorCases}
 * @see {ServiceActivatorErrorHandlingConfig}
 */
export interface ErrorCase<ACTIONS> {
  // The documentation about the conditions is the same as in the NavOptionErrorPageConfig
  // It is partially duplicated here, so that it shows up everywhere in the json schema
  /**
   * The conditions to determine if this error case should be activated.
   *
   * They are similar to the NavOptionConfig conditions.
   * But in difference to those, the state is only available under $.state in these conditions.
   * The error response is available under $.response
   * The response body for error responses is available under $.response.error;
   * The response headers under $.responseHeaders
   *
   * See also the data model for the data/state the JSONPath expressions run against:
   * {@link ErrorCaseConditionsState}
   * See also, the standard NavOptionConfig conditions:
   * {@link NavOptionConfig#conditions}
   */
  conditions?: ConditionE[] | ConditionAdvancedE;

  /**
   * Defines, how the error response data should be mapped to the state.
   *
   * This is similar to the standard response mapping for a successful service activator.
   *
   * @memberof NavServiceActivatorConfig
   */
  errorResponseDataMapping?: ServiceActivatorDataMapping[];

  /**
   * Actions to run, if this error handling gets active. The result of the action is mapped to these flags:
   * true response from the action = ignoreError
   * false response = disableErrorPageNavigation
   */
  actions?: ACTIONS[];

  /**
   * Ignore the result of the actions and handle the error according to the configuration.
   */
  ignoreActionsResult?: boolean;

  /**
   * Ignore this error. Do not go to the error page.
   * Do not stop the navigation. Do not throw the error upwards.
   * Only the responseDataMapping and the actions are still executed.
   */
  ignoreError?: boolean;

  /**
   * Do not run the errorPageNavigation. Do not go to the global error page.
   *
   * - If the call was triggered in a navigation, this stops the current navigation if this error case is detected.
   * This means, that the user will stay on the current page.
   * - If this call was triggered through some other trigger point, the error
   * will be thrown up to the source of the call trigger and has to be handled there.
   */
  disableErrorPageNavigation?: boolean;

  /**
   * Determines the error page to be displayed. Only executed if disableErrorPageNavigation and ignoreError are false.
   * Allows it to evaluate navigation options. Additionally to the state, the full response object is available under the key "$.response"
   * For example the status response code can be accessed like this: "$.response.status"
   *
   * The response body for error responses is available under $.response.error;
   *
   * The state is available under the key "$.state"
   */
  errorPageNavigation?: NavOptionErrorPageConfig[];
}

/**
 * This interface contains all the legacy service activator error handling attributes.
 * Realistically these are not going to be removed for a long time, as they are used by various configurations.
 */
interface LegacyErrorHandlingConfig {
  /**
   * Defines, how the error response data should be mapped to the state.
   * This will be done, before the navigation to the error page is triggered.
   *
   * @deprecated true
   * @deprecationMessage Please switch to the errorResponseDataMapping attribute in the new service activator errorHandling configuration
   */
  errorResponseDataMapping?: ServiceActivatorDataMapping[];

  /**
   * A list of http status codes, that will not be treated as an error by the service activator
   * response handling. For these status codes, the response handling will be executed.
   * This makes it possible to use error status codes for validation errors.
   *
   * The navigation will not be prevented in this case. Use the preventNavigationOnError flag to stay on the page.
   *
   * For a more complex response handling, it is possible to extend the PfeServiceActivatorService
   * and to implement a custom functionality.
   * @deprecated true
   * @deprecationMessage Please switch to the new service activator errorHandling configuration
   */
  serviceActivatorErrorHandlingExcludeStatusCodes?: number[];

  /**
   * When the serviceActivatorErrorHandlingExcludeStatusCodes are used, the navigation is also triggered in case of an error.
   * This flag can be used to activate the previous behavior, where the navigation was not done in case of http error responses.
   * @deprecated true
   * @deprecationMessage Please switch to the new disableErrorPageNavigation attribute in the service activator errorHandling configuration
   */
  preventNavigationOnError?: boolean;
}

/**
 * This interface describes the data model the error case conditions run against.
 * The fields can be accessed in the JSONPath expressions.
 */
export interface ErrorCaseConditionsState {
  state: PfeUserInputState;
  response: HttpErrorResponse;
  responseHeaders: HTTPResponseHeaders;
}

export interface ActiveAsyncServiceActivatorCallForPage {
  /**
   * Unique identifier of service activator.
   * This could be globalConfigId or path.
   */
  id: string;
  callPromise: Promise<HttpResponse<UnknownObject>>;
  dontEmitInProgress: boolean;
  /**
   * Short message to communicate what the system is doing. You can pass an object with
   * the keys `headline` (mandatory) and `subline` (optional). Alternatively, you can directly pass a string,
   * which sets the `headline` of the spinner implicitly.
   */
  displayMessage?: string | ExtendedDisplayMessage;
}

results matching ""

    No results matching ""