RAP from scratch · Lesson 4 of 6
Validations in RAP: failed, reported and messages on the right field
Add behavior to the library (create, update, delete) and validate data on save, with error messages Fiori shows next to the field.
So far the library app is read-only. In this lesson we give it behavior: creating, updating and deleting books. And since we do not want books with 0 pages or 9-star ratings, we add validations.
1. Behavior Definition for the root entity
Right-click ZR_LibBook → New Behavior Definition, type Managed. Adjust the result so it looks like this:
managed implementation in class zbp_r_libbook unique;
strict ( 2 );
define behavior for ZR_LibBook alias Book
persistent table zlib_book
lock master
authorization master ( instance )
etag master LocalLastChangedAt
{
create;
update;
delete;
field ( readonly, numbering : managed ) BookUuid;
field ( readonly ) LocalCreatedBy, LocalCreatedAt, LocalLastChangedBy,
LocalLastChangedAt, LastChangedAt;
field ( mandatory ) BookId, Title, AuthorId;
validation validatePages on save { create; field Pages; }
validation validateRating on save { create; field Rating; }
mapping for zlib_book corresponding
{
BookUuid = book_uuid;
BookId = book_id;
AuthorId = author_id;
CurrencyCode = currency_code;
LocalCreatedBy = local_created_by;
LocalCreatedAt = local_created_at;
LocalLastChangedBy = local_last_changed_by;
LocalLastChangedAt = local_last_changed_at;
LastChangedAt = last_changed_at;
}
}
Line by line, what matters:
| Line | What it does |
|---|---|
managed |
The framework handles reading, saving and locking; you only write business logic |
strict ( 2 ) |
Turns on the strictest syntax and best-practice checks |
persistent table zlib_book |
Where the framework stores the data |
lock master |
Pessimistic lock while someone is editing |
etag master LocalLastChangedAt |
Optimistic lock: if another user changed the book in the meantime, your change is rejected |
numbering : managed |
RAP generates the UUID on create |
mapping … corresponding |
Maps CDS fields to table columns. Fields with the same name (Title/title) do not need to be listed |
validation … on save { create; field Pages; } |
Runs on save if the book is new or Pages changed |
Put the cursor on zbp_r_libbook and use the quick fix (Ctrl+1) so ADT generates the implementation class with empty methods.
2. Behavior Definition for the projection
The projection decides which business object operations this app offers. Right-click ZC_LibBook → New Behavior Definition:
projection;
strict ( 2 );
define behavior for ZC_LibBook alias Book
use etag
{
use create;
use update;
use delete;
}
For an update-only app, you would just drop use create and use delete. The business object stays the same.
3. The validations
In class zbp_r_libbook, Local Types tab, the handler looks like this:
CLASS lhc_book DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Book RESULT result.
METHODS validatePages FOR VALIDATE ON SAVE
IMPORTING keys FOR Book~validatePages.
METHODS validateRating FOR VALIDATE ON SAVE
IMPORTING keys FOR Book~validateRating.
ENDCLASS.
CLASS lhc_book IMPLEMENTATION.
METHOD get_instance_authorizations.
" No restrictions for now: covered in the security lesson
ENDMETHOD.
METHOD validatePages.
READ ENTITIES OF ZR_LibBook IN LOCAL MODE
ENTITY Book
FIELDS ( Pages )
WITH CORRESPONDING #( keys )
RESULT DATA(books).
LOOP AT books INTO DATA(book).
" 1. Clear previous messages from this validation
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_PAGES' ) TO reported-book.
IF book-Pages <= 0.
" 2. Mark the instance as failed: it will not be saved
APPEND VALUE #( %tky = book-%tky ) TO failed-book.
" 3. Explain why, and on which field
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_PAGES'
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'The number of pages must be greater than zero' )
%element-Pages = if_abap_behv=>mk-on ) TO reported-book.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateRating.
READ ENTITIES OF ZR_LibBook IN LOCAL MODE
ENTITY Book
FIELDS ( Rating )
WITH CORRESPONDING #( keys )
RESULT DATA(books).
LOOP AT books INTO DATA(book).
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_RATING' ) TO reported-book.
IF book-Rating > 5.
APPEND VALUE #( %tky = book-%tky ) TO failed-book.
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_RATING'
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Rating goes from 0 to 5; got { book-Rating }| )
%element-Rating = if_abap_behv=>mk-on ) TO reported-book.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
The pattern, step by step
READ ENTITIES … IN LOCAL MODE: a validation only receives the keys (keys) of the affected books, so you read the data first.IN LOCAL MODEskips authorization and feature control checks, because the read is done by the business object itself.WITH CORRESPONDING #( keys )is lesson 1’sCORRESPONDING.%tky: the instance’s “transactional” key. Always use it to refer to a book infailedandreported.failed: says which instances failed. If a validation puts anything here, the whole save is rejected.reported: says why. It carries the message (%msg) and the affected field (%element-Pages), which Fiori highlights in red.%state_area: groups the messages of one validation. At the start you add an empty entry for that area to clear the messages from the previous run: once the user fixes the value, the error goes away. It really pays off with draft mode, but it is a good habit from the start.
Rule of thumb: every
APPEND … TO failed-…comes with anAPPEND … TO reported-…. A failure without a message leaves the user guessing; a message without a failure is just a warning and the save goes through.
Messages from a message class
new_message_with_text is handy while learning. In a real project, texts usually live in a message class so they can be translated:
%msg = new_message( id = 'ZLIB_MESSAGES'
number = '001'
v1 = book-BookId
severity = if_abap_behv_message=>severity-error )
4. Try it
Activate everything and go back to the Service Binding preview (lesson 3). The Create and Delete buttons now show up.
- Create a book with 0 pages and click Save: the save is rejected and the Pages field turns red with your message.
- Enter 350 pages and a rating of 9: now the error is on Rating.
- Fix the rating to 4 and save: the book is created and the messages disappear.
Summary
- The Behavior Definition declares what can be done (
create,update,delete) and which rules apply (validation). - The projection decides which part of that behavior each app offers.
- A validation reads the data, marks the wrong instances in
failedand explains why inreported, on the right field.
This closes the basic block of the series: you have a complete RAP business object with data, service, UI and rules. The next level moves into business logic: custom numbering, determinations and actions.
Get new tutorials by email
One email when something new is published. No spam; unsubscribe anytime.
I will email you to confirm your subscription. Data handled under the privacy policy.