docs

Server Messages in the OData V4 Model

The OData V4 model supports server messages sent via an OData V4 service.

Messages transported via an OData V4 service response are parsed and reported to the message model sap.ui.model.message.MessageModel. An application can retrieve the messages (sap.ui.core.message.Message) and display them in a suitable control, for example in sap.m.MessageView. Server messages can be transported to the client over three different channels which are explained in detail in the following sections. The following table gives an overview how the OData message properties are mapped to the UI5 message:

OData V4 Message UI5 Message Details
`code` `code` language-independent message code
`message` `message` language-dependent message text
`target` `target` - path to the message target - `target` and `additionalTargets` are both mapped to the transition message \(true\)`sap.ui.core.message.Message.target` collection
`additionalTargets`\*
`transition` `persistent` manages the message lifecycle
`numericSeverity`\* `type` classification of end-user messages
`longtextUrl`\* `@Common.longtextUrl`\* `descriptionUrl` a property of `Edm.String` type, which is nullable

*) In the error response this is represented by an instance annotation in the SAP Common vocabulary, com.sap.vocabularies.Common.v1

End user messages contain the following information:

The use of the fields in specific cases is described in the sections below.


Message Types

Messages are classified by two different categories: bound/unbound and state/transition.


Bound and unbound messages

Messages are either bound or unbound: Bound messages are related to OData entities, whereas unbound messages are not related to OData entities. Unbound messages are identified by a missing, i.e. undefined, target in the OData V4 message. This is translated into an empty string in the UI5 message.


State and transition messages

Messages are either state or transition messages:


Combining state/transition and bound/unbound messages

Three different types of messages result from the possible combinations of the state/transition and bound/unbound categories. There cannot be unbound messages referring to the state of an OData entity.

  State Transition
Unbound ![](/docs/04_Essentials/images/loio38d78b4d740c43719a4eb8d80d4184e0_LowRes.png) ![](/docs/04_Essentials/images/loio0d13ebb7aa8b4bf8b5c56acfa02653ef_LowRes.png)
Bound ![](/docs/04_Essentials/images/loio0d13ebb7aa8b4bf8b5c56acfa02653ef_LowRes.png) ![](/docs/04_Essentials/images/loio0d13ebb7aa8b4bf8b5c56acfa02653ef_LowRes.png)

Transport Channels for Messages

There are three different channels for transporting messages to the client:

  1. The error response for transporting unbound and bound transition messages in the error case.

  2. The sap-messages header for transporting unbound and bound transition messages in the success case.

  3. The message property as part of the entity for transporting bound state and transition messages in the success case.

Note:

In the success case, a bound transition message can either be transported in the sap-messages header or in the message property. A message sent in the sap-messages header must not be repeated in the message property, and vice versa.


Messages in error responses

Only transition messages are transported in the error response. The messages may be bound or unbound. Error messages are always reported in the error response in JSON format, as described in the OData JSON Format Version 4.0 in Section 19 Error Response, with the following additions:

A change set with multiple requests only has one error response. In this case, target alone is not sufficient to assign a message to a resource. The error must be assigned to one of the requests via the request’s MIME header Content-ID first. The Content-ID has to be provided in the instance annotation Org.OData.Core.V1.ContentID.

Example:

Request

--changeset_id-1612779902438-25
Content-Type:application/http
Content-ID:0.0
 
PATCH SalesOrderList('0500000005')/SO_2_SOITEM(SalesOrderID='0500000005',ItemPosition='0000000010')?custom-option=value HTTP/1.1
Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true
 
{"Quantity":"0","QuantityUnit":"EA"}
--changeset_id-1612779902438-25
Content-Type:application/http
Content-ID:1.0
 
PATCH SalesOrderList('0500000005')/SO_2_SOITEM(SalesOrderID='0500000005',ItemPosition='0000000020')?custom-option=value HTTP/1.1
Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true
 
{"Quantity":"5","QuantityUnit":"EA"}
--changeset_id-1612779902438-25--

Example:

Response

{
    "error": {
        "message": "Value must be greater than 0",
        "target": "Quantity",
        "@com.sap.vocabularies.Common.v1.additionalTargets": ["ProductID"],
        "@Org.OData.Core.V1.ContentID":"0.0"
    }
}

The sap-messages header

The response of a successful request may contain messages in the sap-messages header. Only transition messages are transported in the sap-messages header. These messages may be bound or unbound. The sap-messages header contains an array of objects that can include:

sap-messages:[
     {
          "code" : "0815",
          "message" : "Delivery date is in the past",
          "numericSeverity" : 3
          "longtextUrl" : "Messages(3)/LongText/$value",
          "target" : "DeliveryDate"
     }
]

Note:

longtextUrl can be a relative or absolute path. Relative paths are treated as relative to the request URL. Absolute paths are treated as relative to the server.

Example:

Request URL: http://<server>:<port>/serviceroot.svc/BusinessPartners(42)/to_Address; longtextUrl: "Messages(3)/LongText/$value"

Result: http://<server>:<port>/serviceroot.svc/BusinessPartners(42)/Messages(3)/LongText/$value

Request URL: http://<server>:<port>/serviceroot.svc/BusinessPartners(42); longtextUrl: "/Messages(3)/LongText/$value"

Result: http://<server>:<port>/Messages(3)/LongText/$value


The message property as part of the response payload

Bound messages may also be transported as a part of the OData entity to which they belong. These messages may be transition or state messages. The OData entity contains its bound messages as collection-valued property of the complex type specified in the description of com.sap.vocabularies.Common.v1.Messages. The target property specifies to which property the message is bound. The application needs to specify in the$select binding parameter whether messages should be returned by the server.

  <ComplexType Name="<name of message type>">
      <Property Name="code" Type="Edm.String" Nullable="false" />
      <Property Name="message" Type="Edm.String" Nullable="false" />
      <Property Name="target" Type="Edm.String" Nullable="true" />
      <Property Name="additionalTargets" Type="Collection(Edm.String)" Nullable="false" />
      <Property Name="transition" Type="Edm.Boolean" Nullable="false" />
      <Property Name="numericSeverity" Type="Edm.Byte" Nullable="false" />
      <Property Name="longtextUrl" Type="Edm.String" Nullable="true" />
  </ComplexType>

The target property may contain a path relative to the entity which contains the message. The target can, for example, refer to a property within that entity. Further targets may be transported in the additionalTargets property. This information is used to highlight UI elements such as input fields if they are bound to properties referenced by a path contained in the target or additionalTargets properties. All responses are checked for bound messages. If there are messages, they are reported to the message model.

Note:

Highlighting of an input field only works if the resolved message target and the binding path of the control are identical. In addition to the OData 4.0 specification, the model normalizes the message targets following these rules:

For bound messages, longtextUrl can be a relative or absolute path. Relative paths are treated as relative to the innermost context path (@odata.context) in the response, or to the request URL if there is no context path. Absolute paths are treated as relative to the server.


Lifecycle Management for State Messages

The lifecycle management for state messages is optimized for a specific orchestration with the server. When messages are selected, the OData V4 server returns all bound messages for the respective entity and its subentities within the same business object. The business object is defined by the first path segment.

The following example uses a sales order with items and related products:

The OData V4 model checks whether the response contains the message property and removes all previous bound state messages from the message model if their target paths start with the path of the entity.

This concept has the following consequences:

Note:

The OpenUI5 V4 ODataModel is agnostic to business objects. The application needs to take care of the proper setup.


Message Severity

The table shows the supported severity values and their mapping to the specific sap.ui.core.MessageType.

numericSeverity Type Comment
1 `sap.ui.core.MessageType.Success` Positive feedback - no action required
2 `sap.ui.core.MessageType.Information` Additional information - no action required
3 `sap.ui.core.MessageType.Warning` Warning - action may be required
4 `sap.ui.core.MessageType.Error` Error - action is required

Accessing the Original Message

The attribute technicalDetails.originalMessage of the message in the message model allows you to access the original message from the back end.


Accessing Additional Request Information

The attribute technicalDetails.httpStatus of an error message in the message model provides the numerical HTTP status code of the corresponding back-end request that failed.


Highlighting Table Rows with Messages

To highlight table rows based on the criticality of the messages for that entity a formatter in controller code is needed. The highlight property of a table row is bound to the collection of messages in the message model and the entity displayed in the row. These binding parts are required to ensure that the formatter is called whenever a change occurs. The formatter itself calls the sap.ui.model.Context#getMessages method, which returns the messages sorted by severity. The following code snippets demonstrate binding and formatter:

Example:

Highlight a table row

<!-- m.Table -->
<Table items="{/SalesOrderList}">
    <columns>
        ...
    </columns>
    <ColumnListItem id="row">
        ...
    </ColumnListItem>
</Table>
 
<!-- table.Table -->
<table:Table rows="{/SalesOrderList}">
    <table:rowSettingsTemplate>
        <t:RowSettings id="row"/>
    </t:rowSettingsTemplate>
</table:Table>

Let messageModel be the named message model. A table row with messages can be highlighted with the following controller code:

Example:

Formatter to highlight a table row

// "MessageType" required from module "sap/ui/core/message/MessageType"

this.byId("row").bindProperty("highlight", {
    formatter: function () {
        var aMessages,
            //formatter MUST be defined in a way that this is the control!
            oRowContext = this.getBindingContext();
 
        if (oRowContext) { // formatter is called with oRowContext null initially
            aMessages = oRowContext.getMessages();
            return aMessages.length ? aMessages[0].type : MessageType.None;
        }
    },
    parts: [
        'messageModel>/',
        { // ensure formatter is called on scrolling
            mode: 'OneTime',
            path: '',
            targetType: 'any'
        }
    ]
});

Related Information

https://github.com/SAP/odata-vocabularies/blob/-/vocabularies/Common.md