From 942af804751d32bcd0aa0c125c06dc66a018c2e2 Mon Sep 17 00:00:00 2001 From: Marc Becker Date: Thu, 11 Jul 2024 12:09:39 +0200 Subject: [PATCH 1/3] Improve Indicating Errors docs Better explain how targets with SAP Fiori work. Addresses https://github.tools.sap/cap/issues/issues/16273 --- java/event-handlers/indicating-errors.md | 34 ++++++++++++++---------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/java/event-handlers/indicating-errors.md b/java/event-handlers/indicating-errors.md index 8c5146a7d..992dcca6d 100644 --- a/java/event-handlers/indicating-errors.md +++ b/java/event-handlers/indicating-errors.md @@ -150,11 +150,18 @@ When SAP Fiori interprets messages it can handle an additional `target` property 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. +A message target is always relative to an input parameter in the event context. +For CRUD-based events this is always the `cqn` parameter, which represents and carries the payload of the request. +For actions or functions a message target can either be relative to the entity the action or function is bound to (represented by the `cqn` parameter) or relative to a parameter of the action or function. +In case of actions and functions SAP Fiori also requires the message target to be prefixed with the action or function's binding parameter or parameter names. +When creating a message target, the correct parameter 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. +As CRUD event handlers are often called from within bound actions or functions (e.g. `draftActivate`), CAP's OData adapter adds a parameter prefix to a message target referring to the `cqn` parameter only when required. + +::: info +When using the `target(String)` API, which specifices the full target as a `String`, no additional parameter prefixes are added by CAP's OData adapter. The `target` value is used as specified. +::: Let's illustrate this with the following example: @@ -204,7 +211,6 @@ Within a `Before` handler that triggers on inserts of new books a message target ``` java @Before public void validateTitle(CdsCreateEventContext context, Books book) { - // ... // event context contains the "cqn" key @@ -217,11 +223,15 @@ public void validateTitle(CdsCreateEventContext context, Books book) { throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified") .messageTarget("cqn", b -> b.get("title")); - // which is the same as (using plain string) + // which is the same as using plain string + // (assuming direct POST request) throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified") .messageTarget("title"); - // ... + // which is the same as using plain string + // (assuming surrounding bound action request, e.g. draftActivate) + throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified") + .messageTarget("in/title"); } ``` @@ -235,8 +245,6 @@ 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()); - - // ... } ``` @@ -254,8 +262,6 @@ public void validateAuthorName(CdsCreateEventContext context, Books book) { // using typed API throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No author name specified") .messageTarget(Books_.class, b -> b.author().name()); - - // ... } ``` @@ -291,8 +297,6 @@ public void validateReview(AddReviewContext context) { // targeting "text" throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid review text") .messageTarget("text"); - - // ... } ``` @@ -317,7 +321,9 @@ public void validateReview(AddReviewContext context) { throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid book description") .messageTarget(Books_.class, b -> b.descr()); - // ... + // which is the same as using plain string + throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid book description") + .messageTarget("in/descr"); } ``` @@ -355,7 +361,7 @@ public class SimpleExceptionHandler implements EventHandler { public void overrideMissingAuthMessage(ErrorResponseEventContext context) { if (context.getException().getErrorStatus().equals(CdsErrorStatuses.EVENT_FORBIDDEN)) { context.getResult().getMessages().set(0, - Message.create(Message.Severity.ERROR, + Message.create(Message.Severity.ERROR, "You cannot execute this action")); } } From fd232118a0df2e44b9e472e7fefb326bb08c1c20 Mon Sep 17 00:00:00 2001 From: Marc Becker Date: Mon, 15 Jul 2024 09:20:19 +0200 Subject: [PATCH 2/3] Update indicating-errors.md --- java/event-handlers/indicating-errors.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/event-handlers/indicating-errors.md b/java/event-handlers/indicating-errors.md index 992dcca6d..447ec83f9 100644 --- a/java/event-handlers/indicating-errors.md +++ b/java/event-handlers/indicating-errors.md @@ -224,12 +224,13 @@ public void validateTitle(CdsCreateEventContext context, Books book) { .messageTarget("cqn", b -> b.get("title")); // which is the same as using plain string - // (assuming direct POST request) + // assuming direct POST request throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified") .messageTarget("title"); // which is the same as using plain string - // (assuming surrounding bound action request, e.g. draftActivate) + // assuming surrounding bound action request with binding parameter "in", + // e.g. draftActivate throw new ServiceException(ErrorStatuses.BAD_REQUEST, "No title specified") .messageTarget("in/title"); } From 23aa6cb1f3b631b1d652446167d3346f34cf01a0 Mon Sep 17 00:00:00 2001 From: Mahati Shankar <93712176+smahati@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:48:24 +0200 Subject: [PATCH 3/3] Update java/event-handlers/indicating-errors.md --- java/event-handlers/indicating-errors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/event-handlers/indicating-errors.md b/java/event-handlers/indicating-errors.md index 447ec83f9..962b97332 100644 --- a/java/event-handlers/indicating-errors.md +++ b/java/event-handlers/indicating-errors.md @@ -152,7 +152,7 @@ Therefore, specifying the `target` can only correctly be used when throwing a `S A message target is always relative to an input parameter in the event context. For CRUD-based events this is always the `cqn` parameter, which represents and carries the payload of the request. -For actions or functions a message target can either be relative to the entity the action or function is bound to (represented by the `cqn` parameter) or relative to a parameter of the action or function. +For actions or functions, a message target can either be relative to the entity to which the action or function is bound (represented by the `cqn` parameter) or relative to a parameter of the action or function. In case of actions and functions SAP Fiori also requires the message target to be prefixed with the action or function's binding parameter or parameter names. When creating a message target, the correct parameter needs to be selected to specify what the relative message target path refers to.