coauthor: ralf.handl
SAP Fiori Elements Object Page Floorplan Draft Scenario Displaying an Error Message
OData Error Message
When building applications with the SAP Cloud Application Programming Model (CAP), generic service providers significantly shorten the service development time by providing many out-of-the-box solutions to recurring tasks allowing you to focus on the specific business logic of your application, thus reducing the overall implementation effort.
Examples of out-of-the-box solutions to recurring tasks — but not limited to — are the following:
These capabilities allow you to develop fully-fledged running services quickly by composing Core Data Services and running simple command-line interface (CLI) commands.
However, things don’t always go straightforward when processing an OData request. HTTP-based applications, such as those using SAP Fiori Elements, send OData requests to backend systems. Assuming that a request payload is invalid or partially invalid, for example, a user might have entered a value in a field that violates a database constraint, but in another field, the user might have entered a valid value. Thus, the valid input can be stored successfully in the backend system, but the invalid input cannot be stored, and it is essential that the user is informed about this error.
This blog post will give you a brief overview of the messaging system for transferring error, warning, and information messages from OData V4 services to HTTP client applications such as those using SAP Fiori Elements.
In the context of HTTP clients and HTTP servers based on CAP — or similar server-side technologies — things don’t always go straightforward when processing an OData request. There are three possible outcomes:
OData defines how to handle the first and second scenarios, but the standard does not mandate how to handle the third scenario. Now focusing on the third scenario, for example, if in an SAP Fiori Elements Object Page Floorplan draft scenario, a user doesn't fill all mandatory text input fields and tries to activate/save the draft to store the active version of a business entity in the back-end system. In that scenario, errors will occur that prevent the entity from being stored, and the user must be able to see possible error messages on the screen.
Block Diagram of Messaging System for Transferring an Error Messages from an OData V4 Services to an SAP Fiori Elements Based Application
The HTTP response body's content adheres to the standard OData specification for an error response body in addition to an SAP-specific format. So errors, warnings, and info messages are transferred to HTTP clients in a format that reflects the most common requirements for messages targeted at users.
The OData HTTP error response body is a JSON object with a single name/value pair named error that contains the following name/value pairs:
Additionally, for extensibility reasons,
implementations can add custom annotations of the form @namespace.termname or property@namespace.termname to any JSON object, where property MAY or MAY NOT match the name of a name/value pair within the JSON object.
In CAP, the error response body is extended using the @Common.numericSeverity instance annotation to add a severity to the message.
Severity Numeric severity Description
Success | 1 | Success — no action required |
Info | 2 | Information — no action required |
Warning | 3 | Warning — action may be required |
Error | 4 | Error — action is required |
The target of an error/warning response is always a relative resource path segment that is appended to the path part of the request URL (for GET, PATCH, PUT, and DELETE requests) or the Location response header (for POST requests that create a new entity), resulting in an OData request URL that is used to retrieve the target of the error message.
For GET, PATCH, PUT, and DELETE requests to a single entity or complex-type instance, the target is:
Given the following CAP based model snippet:
entity Headers {
key ID : UUID;
text : String;
items : Composition of many Items on items.header = $self;
}
entity Items {
key ID : UUID;
header : Association to one Headers @assert.target;
text : String @mandatory;
}
PATCH http://localhost:4004/service-name/Items(ID=7be6d296-9e7a-3505-b72e-4c7b98783578) HTTP/1.1
Accept: application/json;odata.metadata=minimal
Prefer: return=minimal
Content-Type: application/json;charset=UTF-8
{
"text": null
}
HTTP/1.1 400 Bad Request
OData-Version: 4.0
content-type: application/json;odata.metadata=minimal
Connection: close
Content-Length: 98
{
"error": {
"code": "400",
"message": "Value is required",
"target": "text",
"@Common.numericSeverity": 4
}
}
[cds] - PATCH /service-name/Items(ID=7be6d296-9e7a-3505-b72e-4c7b98783578)
[cds] - Error: Value is required {
code: 'ASSERT_NOT_NULL',
target: 'text',
args: [ 'text' ],
entity: 'serviceName.Items',
element: 'text',
type: 'cds.String',
value: null,
numericSeverity: 4,
id: '1090822',
level: 'ERROR',
timestamp: 1653756442547
}
POST http://localhost:4004/service-name/Items HTTP/1.1
Accept: application/json;odata.metadata=minimal
Prefer: return=minimal
Content-Type: application/json;charset=UTF-8
{
"ID": "86b07ae1-2c9b-4a29-953c-b257f5a737f4",
"text": "lorem cillum",
"header_ID": "796e274a-c3de-4584-9de2-3ffd7d42d646"
}
HTTP/1.1 400 Bad Request
OData-Version: 4.0
content-type: application/json;odata.metadata=minimal
Connection: close
Content-Length: 105
{
"error": {
"code": "400",
"message": "Value doesn't exist",
"target": "header_ID",
"@Common.numericSeverity": 4
}
}
[cds] - POST /service-name/Items
[cds] - Error: Value doesn't exist {
code: 'ASSERT_TARGET',
target: 'header_ID',
args: [ 'header_ID' ],
entity: 'serviceName.Items',
element: 'header_ID',
type: 'cds.UUID',
value: '796e274a-c3de-4584-9de2-3ffd7d42d646',
numericSeverity: 4,
id: '1090822',
level: 'ERROR',
timestamp: 1653756615316
}
Notice that in this case, the header managed to-one association is annotated with the @assert.target annotation to check whether the target entity referenced by the association (the reference's target) exists. As the foreign key header_ID input does not have a corresponding primary key in the associated/referenced target entity/table, the OData service respond with an HTTP error message.
POST http://localhost:4004/service-name/Items HTTP/1.1
Accept: application/json;odata.metadata=minimal
Prefer: return=minimal
Content-Type: application/json;charset=UTF-8
{
"header_ID": "796e274a-c3de-4584-9de2-3ffd7d42d646"
}
HTTP/1.1 400 Bad Request
OData-Version: 4.0
content-type: application/json;odata.metadata=minimal
Connection: close
Content-Length: 304
{
"error": {
"code": "400",
"message": "Multiple errors occurred. Please see the details for more information.",
"details": [
{
"code": "400",
"message": "Value is required",
"target": "text",
"@Common.numericSeverity": 4
},
{
"code": "400",
"message": "Value doesn't exist",
"target": "header_ID",
"@Common.numericSeverity": 4
}
]
}
}
[cds] - POST /service-name/Items
[cds] - Error: Multiple errors occurred. Please see the details for more information. {
details: [
{
code: 'ASSERT_NOT_NULL',
message: 'Value is required',
target: 'text',
args: [ 'text' ],
entity: 'serviceName.Items',
element: 'text',
type: 'cds.String',
value: undefined,
numericSeverity: 4
},
{
code: 'ASSERT_TARGET',
message: "Value doesn't exist",
target: 'header_ID',
args: [ 'header_ID' ],
entity: 'serviceName.Items',
element: 'header_ID',
type: 'cds.UUID',
value: '796e274a-c3de-4584-9de2-3ffd7d42d646',
numericSeverity: 4
}
],
id: '1090822',
level: 'ERROR',
timestamp: 1653756684026
}
POST http://localhost:4004/service-name/Headers HTTP/1.1
Accept: application/json;odata.metadata=minimal
Prefer: return=minimal
Content-Type: application/json;charset=UTF-8
{
"ID": "9910905a-b331-419b-a202-7c73588a6637",
"text": "cupidatat anim"
}
PATCH http://localhost:4004/service-name/Headers(ID=9910905a-b331-419b-a202-7c73588a6637) HTTP/1.1
Accept: application/json;odata.metadata=minimal
Prefer: return=minimal
Content-Type: application/json;charset=UTF-8
{
"text": "aliqua sint",
"items": [{
"ID": "f509356d-2e1a-4501-a9fe-5435a46b4531",
"header_ID": "9910905a-b331-419b-a202-7c73588a6637",
"text": null
}]
}
HTTP/1.1 400 Bad Request
OData-Version: 4.0
content-type: application/json;odata.metadata=minimal
Connection: close
Content-Length: 145
{
"error": {
"code": "400",
"message": "Value is required",
"target": "items(ID=f509356d-2e1a-4501-a9fe-5435a46b4531)/text",
"@Common.numericSeverity": 4
}
}
[cds] - POST /service-name/Headers
[cds] - PATCH /service-name/Headers(ID=9910905a-b331-419b-a202-7c73588a6637)
[cds] - Error: Value is required {
code: 'ASSERT_NOT_NULL',
target: 'items(ID=f509356d-2e1a-4501-a9fe-5435a46b4531)/text',
args: [ 'text' ],
entity: 'serviceName.Items',
element: 'text',
type: 'cds.String',
value: null,
numericSeverity: 4,
id: '1090822',
level: 'ERROR',
timestamp: 1653757487211
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
13 | |
7 | |
7 | |
7 | |
6 | |
6 | |
6 | |
5 | |
5 | |
5 |