Sap validation error

Use of Fault Messages and how to implement Fault Messages in an Asynchronous ABAP Proxy interface in detail. Moreover, uses cases and how to monitor Fault Messages.


Notice: A non well formed numeric value encountered in /home/thefoo20/public_html/SAPIntegrationHub.com/wp-content/plugins/crayon-syntax-highlighter/crayon_formatter.class.php on line 118

Notice: A non well formed numeric value encountered in /home/thefoo20/public_html/SAPIntegrationHub.com/wp-content/plugins/crayon-syntax-highlighter/crayon_formatter.class.php on line 119

Notice: A non well formed numeric value encountered in /home/thefoo20/public_html/SAPIntegrationHub.com/wp-content/plugins/crayon-syntax-highlighter/crayon_formatter.class.php on line 118

Notice: A non well formed numeric value encountered in /home/thefoo20/public_html/SAPIntegrationHub.com/wp-content/plugins/crayon-syntax-highlighter/crayon_formatter.class.php on line 119

What is a Fault Message? Fault Messages provide information about application-specific errors that occur in the inbound system. Think about Fault Messages as an acknowledgment from the message receiver to the message sender or the message monitor about the application processing status.

Application-specific errors are errors that occur in the application processing based on business rules. In this article, we will discuss use cases, structure, and implementation steps in detail and learn how to monitor Fault Messages.

SAP Versions used in the illustration:

  • SAP S4 HANA Fashion 1709
  • SAP PO 7.5

Use Cases of Fault Messages in ABAP Proxy

Use case 1: Capturing BAPI/FM Return

Let’s assume a sender system sends a message with invoice information to target system SAP. The invoice is posted from the inbound ABAP proxy class using a BAPI.

What will happen if all information needed to post an invoice in SAP is not sent in the message? Obviously, invoice won’t be posted in the target SAP system. But how does a user identify the issue? What are the return messages from BAPI? If we do not capture the BAPI return messages and pass it back to the message monitor, messages will always show as successful in SXMB_MONI as technically message was processed successfully. (!!!message message messaged success successful)

Keep in mind we are not talking about missing mandatory values in the message. If all mandatory fields filled in the sender message are not populated, either the XML validation or message mapping will throw out a technical error.

We are talking about how to capture application processing issues (BAPI return messages) and send the status of the invoice processing to message monitor. Then, the user will be able to identify application processing (Invoice posting) errors and take necessary actions to correct the issue and reprocess the messages.

To give you another example, let’s assume the FI posting period is not open in SAP. The invoice will not be posted. If fault messages are not captured from the BAPI return, SXMB_MONI will show the message as successfully processed.

Use Case 2: Message Validations

Let’s assume you need to validate the inbound message content based on business rules before processing the message in SAP. How do we capture the status of the validation in message monitor?

If validation failures are not passed to SXMB_MONI as an exception, the message will always show as successfully processed. In this case, business users won’t be able to identify which messages actually posted successfully in SAP and which messages did not pass the validation.

Therefore, you need to capture error messages of the validation and raise them as an exception.

For example, take the exchange rates interface we built previously. This interface updates exchange rates in SAP via a BAPI implemented in the proxy class. Now we have a requirement to validate the message content before calling the BAPI. “Valid from date” in the exchange rates input message should not be in the past.

Structure or Format of Fault Messages in SAP PI and ABAP Proxy

Standard Fault Messages in SAP PI/PO have a predefined format. But of course you can enhance this format to add additional fields and segments if necessary.

Standard Structure of Fault Messages in SAP PI

Standard Fault Message Type has 3 main segments. They are two fields named faultText and faultUrl and a table named faultDetail.

Standard Fault Message Structure Overview Diagram

Standard Fault Message Structure

faultText:

This parameter provides a short description of the application error. It provides an overall status of message processing. For example, for use case 1, we can define messages as “Invoice not posted”.

In use case 2, we can define them as “Exchange rates not updated in SAP”

faultUrl:

This is the Url where user can find more information about the error in faultText.

faultDetail:

This is a table parameter which can hold multiple error/warning/information messages from the application processing. For example, BAPI can return multiple messages about invoice processing or application processing. We can include all those messages to the proxy run-time monitor so the user can find all the details of the message processing.

Structure of the faultDetail includes four fields:

  • severity
  • text
  • url
  • id
severity

You can define the severity of the message in this field. Message types such as E (Error), I (information), W (Warning), S (Success) can be assigned to this field. This correlates to the messages type in ABAP MSGTY.

text

Message text.

url

Url to the long text of the message in ‘text‘.

id

You can assign the message ID here. For example, message class and message number of the error in SAP. Assuming our message class is SD and message ID is 002, you can set the ID as SD(002).

This correlates to how the message class and message numbers are defined in transaction se91.


Example of Fault Message Implementation

To demonstrate the functionality of Fault Messages I will re-use the exchange rates interface file to proxy example. This interface updates the exchange rates in SAP using function module ‘BAPI_EXCHANGERATE_CREATE’.

Have a look at the implementation of the exchange rates interface before proceeding.

We will modify the exchange rates interface to return application processing errors to SXMB_MONI. Let’s assume if the “Valid from” date (VALID_FROM) of the exchange rates record in the file is in the past, we do not want to update exchange rates in SAP. Records which do not satisfy the “Valid from” date validation should be visible in SXMB_MONI as error messages.

Pseudo Code of the Validation Logic in Proxy Class

“Valid from date” validation should be implemented in the Proxy class. Here’s how the processing logic looks like.

Proxy class ABAP logic pseudo code for fault message implementation

Proxy class ABAP logic pseudo code

Fault Messages Implementation Steps

Now we will look at all the steps of Fault Messages implementation in an inbound interface. The differences in steps between the Asynchronous Proxy interface we previously implemented without Fault Message and this interface with Fault Messages are,

  • Creation of Data Type and a Message Type of standard Fault Message type.
  • Changing the Inbound Service Interface to reflect response Fault Data.
  • Creation of a new Operation Mapping.

Full list of Fault Message implementation steps are as follows,

  1. Configure Proxy connectivity between SAP PI/PO and SAP back-end system.
  2. Create standard Fault Message’s Data Type and Message Type.
  3. Create sender Data Type and Message Type.
  4. Create receiver Proxy Data Type and Message Type.
  5. Define the Inbound Service Interface with Fault Message.
  6. Implement Message Mapping and Operation Mapping.
  7. Generate Proxy Class in SAP back-end system.
  8. Implement ABAP logic to return application errors to SXMB_MONI.
  9. Configure the iFlow.

As all the steps, except for step 2, step 5, and step 8, are the same for Fault Message implementation as the original exchange rates interface, I will demonstrate only the detail of steps 2, 5 and 8 in this article. You can refer to the previous post to check more information about other steps.

Step 2: Create Fault Message

First, create two data types for FaultData and Log Data. You can copy any standard fault message data types to your custom SWCV and namespace.

Data Type ExchangeLogData

ExchangeLogData Data Type in ESR
ExchangeLogData Data Type

Data Type ExchangeFaultData

ExchangeFaultData Data Type in ESR in SAP PI PO
ExchangeFaultData Data Type

Create Fault Message Type

Create a Fault Message Type by assigning the Fault Data Type ExchangeFaultData created previously.

To create the Fault Message Type, first, right-click on the namespace and select “Fault Message Type” from the list of objects.

Right click and select new object to create Fault Message Type in ESR.
Create Fault Message Type in ESR

Then assign the Data Type ExchangeFaultData we created in step 2 to the Fault Message Type.

Fault Message structure in ESR with header and fault log data
Fault Message structure in ESR

Step 5: Define the Inbound Service Interface with Fault Message

Create the Inbound Service Interface and assign the Fault Message Type we created in Step 3.

The name of the Inbound Service Interface in this example is ‘ExchangeRateswithFaultMessage_Inb_Async’.

Inbound Service Interface with Fault Message assigned
Inbound Service Interface with Fault Message assigned

Step 8: Implement ABAP logic in Proxy Class

Create the Inbound proxy class the usual way using SPROXY transaction.

Inbound Service Interface and Proxy class in SPROXY Transaction in SAP back-end system with Fault message types
Inbound Service Interface and Proxy class in SPROXY Transaction

Go to Proxy implementation class and you will be able to view the exception class ZCX_FAULT_MESSAGE in the method signature.

Proxy class with zcx_fault_messages exception class in transaction se24
Proxy class with zcx_fault_messages exception class
Proxy class with zcx_fault_messages exception class in transaction se24
Proxy class with zcx_fault_messages exception class

Notice that the Fault Message Type we created in SAP PI/PO ESR is generated as a DDIC structure in SAP back end.

Fault Message DDIC structure in SAP back-end system under zcx_fault_message class in transaction se24.
Fault Message DDIC structure in SAP back-end system under zcx_fault_message class

DDIC structure ZEXCHANGE_FAULT_DATA correlates to FaultMessage Message Type in ESR.

Exchange Fault Message DDIC structure in SAP back-end
Exchange Fault Message DDIC structure in SAP back-end

Also, DDIC structure ZEXCHANGE_LOG_DATA corresponds to ExchangeLogData Data Type.

FaultLogData Message Type as a DDIC structure in SAP back-end system
FaultLogData Message Type as a DDIC structure in SAP back-end system

Proxy Class ABAP Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

  METHOD zii_exchange_rateswith_fault_m~exchange_rateswith_fault_messa.

*** **** INSERT IMPLEMENTATION HERE **** ***

    DATA: lwa_exch_rate  LIKE LINE OF inputexchange_ratesexch_rate,

          lwa_bapi_input TYPE bapi1093_0,

          lwa_input      LIKE input.

    DATA: lt_return         TYPE TABLE OF bapiret2,

          lwa_standard_data TYPE  zexchange_fault_data,

          lwa_error_detail  TYPE zexchange_log_data.

    DATA: lv_error_flag TYPE c VALUE IS INITIAL.

*Assign proxy input message to a local variable

    lwa_input = input.

*Validate if data is in the past

*Loop data records of in coming proxy message

    LOOP AT lwa_inputexchange_ratesexch_rate INTO lwa_exch_rate.

*Check if from date is in the past

      IF lwa_exch_ratevalid_from < sydatum.

        lv_error_flag = abap_true.

*Append errors to exception table

        lwa_standard_datafault_text   = ‘Error Ooccured, exchanges rates were not posted in SAP’.

        lwa_standard_datafault_url   = ‘https://sapintegrationhub.com’.

        CLEAR lwa_error_detail.

        lwa_error_detailseverity       = ‘High’.

        CONCATENATE ‘Date’ lwa_exch_ratevalid_from ‘is in the past’ INTO lwa_error_detailtext SEPARATED BY space.

        lwa_error_detailid = sytabix.   «Record number of the input message

        lwa_error_detailurl            = ‘https://sapintegrationhub.com’.

        APPEND lwa_error_detail TO lwa_standard_datafault_detail.

      ENDIF.

    ENDLOOP.

*if no errors found update the exchanges rates

if lv_error_flag is INITIAL.

    LOOP AT lwa_inputexchange_ratesexch_rate INTO lwa_exch_rate.

      MOVE-CORRESPONDING lwa_exch_rate TO lwa_bapi_input.

      CALL FUNCTION ‘BAPI_EXCHANGERATE_CREATE’

        EXPORTING

          exch_rate = lwa_exch_rate

          upd_allow = ‘X’.

    ENDLOOP.

*Else send acknowledgment

ELSEIF lv_error_flag = abap_true.

    RAISE EXCEPTION TYPE zcx_fault_message

      EXPORTING

*       textid   = *

*       previous = *

*       automatic_retry = *

*       controller      = *

*       no_retry =

        standard = lwa_standard_data.

ENDIF.

  ENDMETHOD.


Test Fault Message using PI/PO Test Tool

Test Case

We will trigger a message with valid date in the past. In the test message <VALID_FROM> date is 2019-05-01 which is in the past.

Test Message

<?xml version=«1.0» encoding=«UTF-8»?>

<ns1:ExchangeRates xmlns:ns1=«urn:Target_System:ExchangeRates»>

<EXCH_RATE>

<RATE_TYPE>M</RATE_TYPE>

<FROM_CURR>USD</FROM_CURR>

<TO_CURRNCY>EUR</TO_CURRNCY>

<VALID_FROM>2019-05-01</VALID_FROM>

<EXCH_RATE>0.89</EXCH_RATE>

<FROM_FACTOR>1</FROM_FACTOR>

<TO_FACTOR>1</TO_FACTOR>

<EXCH_RATE_V>0.0</EXCH_RATE_V>

<FROM_FACTOR_V>0</FROM_FACTOR_V>

<TO_FACTOR_V>0</TO_FACTOR_V>

</EXCH_RATE>

</ns1:ExchangeRates>

Monitor Interface Using SXMB_MONI

Go to transaction SXMB_MONI to monitor the application processing status of the message. You will notice it has been flagged as an error message.

You will be able to see the message in status “Application Error – Manual Restart Possible”.

If you need to analyze the behavior of the Proxy ABAP logic at runtime, set an external debugging break-point and trigger the interface from PI.

Message overall status in SXMB_MONI initial screen. Application error with manual restart possible status
Message overall status in SXMB_MONI

Business users will be able to easily identify messages which were not posted in SAP due to ABAP validation not being satisfied. While messages which processed successfully will be in a successful status while messages failed due to validation will be flagged in an error status.


How to Monitor Fault Message Details in SXMB_MONI?

To view the message processing detail and payload, double click on the message in SXMB_MONI to go to the detail view.

You can view the Inbound Message and Call Inbound Proxy messages in the navigation tree.

SXMB_MONI XML message  navigation tree with inbound message and proxy return messages.
SXMB_MONI XML message navigation tree

Go to Main Document section of Call Inbound Proxy message to view the error detail. This detail you can view here, we appended from the ABAP proxy logic.

Fault Message data displayed in SXMB_MONI under main document section of proxy message
Fault Message data displayed in SXMB_MONI under main document section

Hope this illustration cleared any doubts you had about the use of Fault Messages in SAP. If you have any questions, please leave a comment below!

SAP ABAP Class CX_ST_VALIDATION_ERROR (Validation Error in a Simple Transformation)

Hierarchy


SAP_BASIS (Software Component) SAP Basis Component

  


BC-ABA-LA (Application Component) Syntax, Compiler, Runtime

    


S_ABAP_EXCEPTIONS (Package) ABAP Runtime Errors as System Exceptions

Meta Relationship — Using
# Relationship type Using Short Description Created on
1 Inheritance (c INHERITING FROM c_ref)  CX_ST_ERROR Error Performing Simple Transformation 20090123
Properties
Class CX_ST_VALIDATION_ERROR  
Short Description Validation Error in a Simple Transformation    
Super Class CX_ST_ERROR Error Performing Simple Transformation 
Instantiability of a Class Public 
Final    
General Data
Message Class    
Program status     
Category 40  Exception Class 
Package S_ABAP_EXCEPTIONS   ABAP Runtime Errors as System Exceptions 
Created 20090123   SAP 
Last change 20090618   SAP 
Shared Memory-enabled    
Fixed point arithmetic    
Unicode checks active    
Forward declarations

Class CX_ST_VALIDATION_ERROR has no forward declaration.

Interfaces

Class CX_ST_VALIDATION_ERROR has no interface implemented.

Friends

Class CX_ST_VALIDATION_ERROR has no friend class.

Attributes
# Attribute Level Visibility Read only Typing Associated Type Initial Value Description Created on
1 CX_ST_VALIDATION_ERROR Constant Public Type reference (TYPE) SOTR_CONC ‘001560AA0E0802DCA994CD7E7D3E852A’ 20090123
2 FRACTION_DIGITS Instance attribute Public Type reference (TYPE) STRING Facet «fractionDigits» 20090206
3 GENERIC_WITH_VALUE Constant Public Type reference (TYPE) SOTR_CONC ‘001A4BD2B24A02ECB0E2330315DE1640’ 20090123
4 MAX_EXCLUSIVE Instance attribute Public Type reference (TYPE) STRING Facet «maxExclusive» 20090206
5 MAX_INCLUSIVE Instance attribute Public Type reference (TYPE) STRING Facet «maxInclusive» 20090206
6 MIN_EXCLUSIVE Instance attribute Public Type reference (TYPE) STRING Facet «minExclusive» 20090206
7 MIN_INCLUSIVE Instance attribute Public Type reference (TYPE) STRING Facet «minInclusive» 20090206
8 TOTAL_DIGITS Instance attribute Public Type reference (TYPE) STRING Facet «totalDigits» 20090206
9 TYPE Instance attribute Public Type reference (TYPE) STRING Types 20090206
10 VALUE Instance attribute Public Type reference (TYPE) STRING Value 20090123
Methods
# Method Level Visibility Method type Description Created on
1 CONSTRUCTOR Instance method Public Constructor CONSTRUCTOR 20090123
Events

Class CX_ST_VALIDATION_ERROR has no event.

Types

Class CX_ST_VALIDATION_ERROR has no local type.

Method Signatures

Method CONSTRUCTOR Signature

# Type Parameter Pass Value Optional Typing Method Associated Type Default value Description Created on
1 Importing FRACTION_DIGITS Call by reference Type reference (TYPE) STRING 20090206
2 Importing MAX_EXCLUSIVE Call by reference Type reference (TYPE) STRING 20090206
3 Importing MAX_INCLUSIVE Call by reference Type reference (TYPE) STRING 20090206
4 Importing MIN_EXCLUSIVE Call by reference Type reference (TYPE) STRING 20090206
5 Importing MIN_INCLUSIVE Call by reference Type reference (TYPE) STRING 20090206
6 Importing PREVIOUS Call by reference Attribute reference (LIKE) PREVIOUS 20090123
7 Importing ST_IC Call by reference Type reference (TYPE) I 20090123
8 Importing ST_PROGNAME Call by reference Type reference (TYPE) STRING 20090123
9 Importing ST_TIMESTAMP Call by reference Type reference (TYPE) SCX_ST_TSTAMP 20090123
10 Importing TEXTID Call by reference Attribute reference (LIKE) TEXTID 20090123
11 Importing TOTAL_DIGITS Call by reference Type reference (TYPE) STRING 20090206
12 Importing TYPE Call by reference Type reference (TYPE) STRING 20090206
13 Importing VALUE Call by reference Type reference (TYPE) STRING 20090123
14 Importing XML_OFFSET Call by reference Type reference (TYPE) I 20090123
15 Importing XML_PATH Call by reference Type reference (TYPE) STRING 20090123

Method CONSTRUCTOR on class CX_ST_VALIDATION_ERROR has no exception.

History
Last changed by/on SAP  20090618 
SAP Release Created in 720   

    This section describes the error handling capabilities provided by the CAP Java SDK.

    Content

    Overview

    The CAP Java SDK provides two different ways to indicate errors:

    • By throwing an exception: This completely aborts the event processing and rollbacks the transaction.
    • By using the Messages API: This adds errors, warnings, info, or success messages to the currently processed request, but doesn’t affect the event processing or the transaction.

    The message texts for both exceptions and the Messages API can use formatting and localization.

    Exceptions

    Any exception that is thrown by an event handler method aborts the processing of the current event and causes any active transaction to be rolled back.
    To indicate further details about the error, such as a suggested mapping to an HTTP response code, the CAP Java SDK provides a generic unchecked exception class, called ServiceException.
    It’s recommended to use this exception class, when throwing an exception in an event handler.

    When creating a new instance of ServiceException you can specify an ErrorStatus object, through which an internal error code and a mapping to an HTTP status code can be indicated.
    An enum ErrorStatuses exists, which lists many useful HTTP error codes already.
    If no such error status is set when creating the ServiceException, it defaults to an internal server error (HTTP status code 500).

    // default error status
    throw new ServiceException("An internal server error occurred", originalException);
    // specifying an error status
    throw new ServiceException(ErrorStatuses.CONFLICT, "Not enough stock available")
    // specifying an error status and the original exception
    throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No book title specified", originalException);
    

    The OData V4 adapter turns all exceptions into an OData error response to indicate the error to the client.

    Messages

    The Messages API allows event handlers to add errors, warnings, info, or success messages to the currently processed request. Adding info, warning or success messages doesn’t affect the event processing or the transaction. For error messages by default a ServiceException is thrown at the end of the Before handler phase. You can change this by setting cds.errors.combined to false.

    The Messages interface provides a logger-like API to collect these messages. Additional optional details can be added to the Message using a builder API.
    You can access the Messages API from the Event Context:

    context.getMessages().success("The order was successfully placed");
    

    In Spring, you can also access it using Dependency Injection:

    @Autowired
    Messages messages;
    
    messages.warn("No book title specified");
    messages.error("The book is no longer available").code("BNA").longTextUrl("/help/book-not-available");
    

    The OData V4 adapter collects these messages and writes them into the sap-messages HTTP header by default.
    However, when an OData V4 error response is returned, because the request was aborted by an exception, the messages are instead written into the details section of the error response.
    Writing the messages into explicitly modeled messages properties isn’t yet supported.

    SAP Fiori uses these messages to display detailed information on the UI. The style how a message appears on the UI depends on the severity of the message.

    Throwing a ServiceException from Error Messages

    It is also possible to throw a ServiceException from error messages. This can, for example, be useful to cancel a request after collecting multiple validation errors. The individual validation checks will collect error messages in the Messages API. After the validation checks have been run, you call the throwIfError() method. Only if error messages have been collected, this method cancels the request with a ServiceException:

    // throw a ServiceException, if any error messages have been added to the current request
    messages.throwIfError();
    

    If there are any collected error messages, this method creates a ServiceException from one of these error messages.
    The OData V4 adapter turns this exception into an OData error response to indicate the error to the client. The remaining error messages are written into the details section of the error response.

    If the CDS property cds.errors.combined is set to true (default), Messages.throwIfError() is automatically called at the end of the Before handler phase to abort the event processing in case of errors. It is recommended to use the Messages API for validation errors and rely on the framework calling Messages.throwIfError() automatically, instead of throwing a ServiceException.

    Formatting and Localization

    Texts passed to both ServiceException and the Messages API can be formatted and localized.
    By default you can use SLF4J’s messaging formatting style to format strings passed to both APIs.

    // message with placeholders
    messages.warn("Can't order {} books: Not enough on stock", orderQuantity);
    // on ServiceException last argument can always be the causing exception
    throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid number: '{}'", wrongNumber, originalException);
    

    You can localize these strings, by putting them into property files and passing the key of the message from the properties file to the API instead of the message text.

    When running your application on Spring, the CAP Java SDK integrates with Spring’s support for handling text resource bundles. This handling by default expects translated texts in a messages.properties file under src/main/resources.

    The texts defined in the resource bundles can be formatted based on the syntax defined by java.text.MessageFormat.
    When the message or exception text is sent to the client it’s localized using the client’s locale, as described here.

    messages.properties

    my.message.key = This is a localized message with {0} parameters
    

    messages_de.properties

    my.message.key = Das ist ein übersetzter Text mit {0} Parametern
    
    // localized message with placeholders
    messages.warn("my.message.key", paramNumber);
    // localized message with placeholders and additional exception
    throw new ServiceException(ErrorStatuses.BAD_REQUEST, "my.message.key", paramNumber, originalException);
    

    Exporting the Default Messages

    As of CAP Java 1.10.0, you can extract the available default messages as a resource bundle file for further processing (for example, translation). Therefore, the delivery artifact cds-services-utils contains a resource bundle cds-messages-template.properties with all available error codes and default messages. Application developers can use this template to customize error messages thrown by the CAP Java SDK in the application.

    1. Download the artifact or get it from the local Maven repository in ~/.m2/repository/com/sap/cds/cds-services-utils/<VERSION>/cds-services-utils-<VERSION>.jar.
    2. Extract the file.
       jar -f cds-services-utils-<VERSION>.jar -x cds-messages-template.properties
      

      <VERSION> is the version of CAP Java you’re using in your project.

    3. Rename the extracted file cds-messages-template.properties appropriately (for example, to cds-messages.properties) and move it to the resource directory of your application.
    4. In your Spring Boot application, you have to register this additional resource bundle accordingly.

    Now, you’re able to customize the stack error messages in your application.

    With new CAP Java versions, there could be also new or changed error messages in the stack. To identify these changes, export cds-messages-template.properties from the new CAP Java version and compare it with the previous version using a diff tool.

    Target

    When SAP Fiori interprets messages it can handle an additional target property, which, for example, specifies which element of an entity the message refers to. SAP Fiori can use this information to display the message along the corresponding field on the UI.
    When specifying messages in the sap-messages HTTP header, SAP Fiori mostly ignores the target value.
    Therefore, specifying the target can only correctly be used when throwing a ServiceException as SAP Fiori correctly handles the target property in OData V4 error responses.

    A message target is always relative to an input parameter in the event context. For CRUD-based events this is usually the cqn parameter you can find in the underlying map of the event context. For action or function events you find their input parameters in the map, as well.

    Therefore, when creating a message target, one of these event context parameters needs to be selected to specify what the relative message target path refers to.

    By default a message target always refers to the CQN statement of the event. In case of CRUD events this is the targeted entity. In case of bound actions and functions this is the entity that the action or function was bound to.

    Let’s illustrate this with the following example:

    entity Books : cuid, managed {
        title  : localized String(111);
        descr  : localized String(1111);
        author : Association to Authors;
    }
    
    entity Authors : cuid, managed {
        name         : String(111);
        dateOfBirth  : Date;
        placeOfBirth : String;
        books        : Association to many Books
                           on books.author = $self;
    }
    
    entity Reviews : cuid, managed {
        book   : Association to Books;
        rating : Rating;
        title  : String(111);
        text   : String(1111);
    }
    
    service CatalogService {
        type Reviewer {
            firstName : String;
            lastName  : String;
        }
        entity Books as projection on my.Books excluding {
            createdBy,
            modifiedBy
        } actions {
            action addReview(reviewer : Reviewer, rating : Integer, title : String, text : String) returns Reviews;
        };
    }
    

    Here, we have a CatalogService that exposes et al. the Books entity and a Books bound action addReview.

    CRUD Events

    Within a Before handler that triggers on inserts of new books a message target can only refer to the cqn parameter:

    @Before
    public void validateTitle(CdsCreateEventContext context, Books book) {
    
        // ...
    
        // event context contains the "cqn" key
    
        // implicitly referring to cqn
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified")
            .messageTarget(b -> b.get("title"));
    
        // which is equivalent to explicitly referring to cqn
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified")
            .messageTarget("cqn", b -> b.get("title"));
    
        // which is the same as (using plain string)
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified")
            .messageTarget("title");
    
        // ...
    }
    

    Instead of using the generic API for creating the relative message target path, CAP Java SDK also provides a typed API backed by the CDS model:

    @Before
    public void validateTitle(CdsCreateEventContext context, Books book) {
        // ...
    
        // implicitly referring to cqn
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified")
            .messageTarget(Books_.class, b -> b.title());
    
        // ...
    }
    

    This also works for nested paths that with associations:

    @Before
    public void validateAuthorName(CdsCreateEventContext context, Books book) {
        // ...
    
        // using un-typed API
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified")
            .messageTarget(b -> b.to("author").get("name"));
    
        // using typed API
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No author name specified")
            .messageTarget(Books_.class, b -> b.author().name());
    
        // ...
    }
    

    Bound Actions and Functions

    The same applies to message targets that refer to an action or function input parameter:

    @Before
    public void validateReview(AddReviewContext context) {
        // ...
    
        // event context contains the keys "reviewer", "rating", "title", "text",
        // which are the input parameters of the action "addReview"
    
        // referring to action parameter "reviewer", targeting "firstName"
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid reviewer first name")
            .messageTarget("reviewer", r -> r.get("firstName"));
    
        // which is equivalent to using the typed API
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid reviewer first name")
            .messageTarget("reviewer", Reviewer_.class, r -> r.firstName());
    
        // targeting "rating"
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid review rating")
            .messageTarget("rating");
    
        // targeting "title"
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid review title")
            .messageTarget("title");
    
         // targeting "text"
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid review text")
            .messageTarget("text");
    
        // ...
    }
    

    If a message target refers to the cqn of the event context, for bound actions and functions that means, that the message target path is relative to the bound entity.

    For the addReview action that is the Books entity, as in the following example:

    @Before
    public void validateReview(AddReviewContext context) {
        // ...
    
        // referring to the bound entity `Books`
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid book description")
            .messageTarget(b -> b.get("descr"));
    
        // which is equivalent to
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid book description")
            .messageTarget(b -> b.descr());
    
        // or (using the typed API, referring to "cqn" implicitly)
        throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid book description")
            .messageTarget(Books_.class, b -> b.descr());
    
        // ...
    }
    

    The previous examples showcase the target creation with the ServiceException API, but the same can be done with the Message API and the respective target(...) methods.

    Error Handler

    An exception thrown in an event handler will stop the processing of the request. As part of that, protocol adapters trigger the ERROR_RESPONSE event of the Application Lifecycle Service. By default, this event combines the thrown exception and the messages from the RequestContext in a list to produce the error response. OData V4 and V2 protocol adapters will use this list to create an OData error response with the first entry being the main error and the remaining entries in the details section.

    You can add event handlers using the @After phase for the ERROR_RESPONSE event to augment or change the error responses:

    • Method getException() of ErrorResponseEventContext returns the exception that triggered the event.
    • Method getEventContexts() of ServiceException contains the list of event contexts, identifying the chain of processed events that led to the error. The first entry in the list is the context closest to the origin of the exception.

    You can use the exception and the list of events contexts (with service, entity and event name) to selectively apply your custom error response handling. Some exceptions, however, may not be associated with a context and the list of contexts will be empty for them.

    The list of messages available via getResult().getMessages() of the ErrorResponseEventContext contains the messages (see Messages API) the protocol adapter will use to generate the final error response. You can remove, reorder or add new messages to this list by using Message.create() . You can also override the resulting HTTP status with method getResult().setHttpStatus(). Use only statuses that indicate errors, meaning status code 400 or higher.

    Don’t create new messages in the Messages of the RequestContext (also available through context.getMessages()). They will not be included in the response. Only the result provided by the ErrorResponseEventContext is considered by the protocol adapter.

    In case your implementation of the error handler throws an exception, returns no messages or sets a non-error HTTP status, the error response will default to a generic internal server error with HTTP status 500 and will not display any error details.

    The following example of a simple error handler overrides the standard message text of authorization errors. Technically, it replaces the first message, that is the main error in OData, in the response with a new message that has a custom text, only for exceptions with error code CdsErrorStatuses.EVENT_FORBIDDEN.

    @Component
    @ServiceName(ApplicationLifecycleService.DEFAULT_NAME)
    public class SimpleExceptionHandler implements EventHandler {
    
      @After
      public void overrideMissingAuthMessage(ErrorResponseEventContext context) {
        if (context.getException().getErrorStatus().equals(CdsErrorStatuses.EVENT_FORBIDDEN)) {
            context.getResult().getMessages().set(0, Message.create(Severity.ERROR, "You cannot execute this action"));
        }
      }
    }
    

    The second example shows how to override validation messages triggered by the annotation @assert.range for a certain entity. The exception triggered by CAP contains a reference to the event context that can be used to identify the target entity. The target of each message can be used to identify the affected field, but keep in mind that targets are always relative to the root entity of the request. That means in case of deep inserts or updates, you need to match not only the entity that has annotations but also the parent entities.

    @Component
    @ServiceName(ApplicationLifecycleService.DEFAULT_NAME)
    public class ExceptionServiceErrorMessagesHandler implements EventHandler {
    
      @After
      public void overrideValidationMessages(ErrorResponseEventContext context) {
        context.getException().getEventContexts().stream().findFirst().ifPresent(originalContext -> {
          if (Books_.CDS_NAME.equals(originalContext.getTarget().getQualifiedName())) { // filter by entity
            List<Message> messages = context.getResult().getMessages();
            for(int i=0; i<messages.size(); ++i) {
              Message message = messages.get(i);
              if (CdsErrorStatuses.VALUE_OUT_OF_RANGE.getCodeString().equals(message.getCode())) { // filter by error code
                if (Books.PRICE.equals(message.getTarget().getRef().targetSegment().id())) { // filter by target
                  messages.set(i, Message.create(Severity.ERROR, "The exceptional price is not in defined range!", message));
                } else if (Books.STOCK.equals(message.getTarget().getRef().targetSegment().id())) {
                  messages.set(i, Message.create(Severity.ERROR, "The exceptional stock of specified items is not available!", message));
                }
              }
            }
          }
        });
      }
    }
    

    If you replace the message with a new one, make sure that you copy the code and target of the original. Otherwise, SAP Fiori clients may not be able to display them properly. Use method Message.create(Severity severity, String text, Message message) to create a new message and copy all additional attributes from the existing one.

    Having correct product information is of great importance for your business. Especially when you try to sell products. How would you be able to sell anything with just an article number? I don’t think a product without any informative data will sell very well. But how can we make sure all required data is available before we put the products on our website? Can we check if data is correct?

    When using the SAP Commerce Backoffice for managing your product information, you can use the included validation framework to check for missing or invalid data.

    The validation framework provides:

    • Different types of validations for the most common checks. Is data provided? Is the data of the right format? Is a provided number not negative? And many more.
    • Deny or inform the user of incorrect data according to the given severity level.
    • Easy configuration

    How does it work?

    In Backoffice you will be able to configure specific validations. These validations can be either for the whole product or only for a specific element of the product. Validations will be executed when you open a product in Backoffice or when you save a product. As a user you will be notified immediately of incorrect data.

    According to the severity level configured with the validations data will be saved of denied. You can set a severity level for each validation which results in different behavior when you save incorrect data.

    There are 3 different types of severity levels:

    • Info: This type is used to inform the user of minor mistakes. After saving the data you will be notified.
    • Warning: This type is for more serious mistakes. As a user you can save to data, but you need to confirm that you want to save it anyway.
    • Error: This type is used for critical data. You won’t be able to save the product as long as this value is not correct.

     

    When configuring a validation, you must choose between two types of validations:

    • Attribute validation
    • Type validation

    The main difference is the level they operate in. An attribute validation will only validate an attribute of a product. This type of validation does not have any context of the product and will only be able to tell if the value itself is correct. As an example, you can use this type to check if an EAN number contains 13 digits.
    A type validation is basically a validation that can check the product in its context. This type of validation will be able to check if different values inside the product conflict with each other. In most cases you need a custom implementation for this type of validation.

    Real world example

    For your product you require at least some relevant information like:

    • An EAN number that contains at least 13 digits
    • A price that is not negative
    • A description that is at least 20 characters long and does not exceed 200 characters

    In order to meet the required conditions, we can configure the following validation constraints:

    • For the EAN number we can configure a Regex-constraint with a regex pattern of “d{13}”. This assures you have 13 digits.
    • For the price we can configure a Min-constraint with a minimum of 0. This assures that you will not have negative value.
    • For the description we can configure a Size-constraint with a minimum value of 20 and a maximum value of 200. This assures that there is a value between 20 and 200 characters.

    The “EAN number” is an identifier for the product and “Price” is mandatory to be able to sell the product. Therefore, I would suggest setting the severity level for the “EAN number” and “Price” to ERROR. This assures that these requirements are met before you can save the product. The severity level for “description” could be set to WARNING because it is not critical to have a description, but it certainly adds value to your product information.

    Implementation

    Validations can be configured using the administration perspective in Backoffice. All existing validations are shown under System->Validation->Constraints. You will also be able to add new validations from this window using the plus (+) icon.

    For the most common validations you will find a suitable type in the dropdown. I used a few in my example but there are many more.
    In the second tab you will be able to set the severity level and the message.

    After saving the validation you need to reload the validation framework to active the newly created validation. This can be done using the “Reload validation engine” button.

    Now when you save a product without a proper value you will receive a message to tell you what’s wrong.

    Понравилась статья? Поделить с друзьями:
  • Sap remote function call error
  • Sap error m7021
  • Sap error ki235
  • Sao fb fatal error
  • Sanyo error codes