Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Thajunniza
Product and Topic Expert
Product and Topic Expert
3,832
Input validation is a crucial aspect of developing robust and secure applications. In SAP Cloud Application Programming Model (CAP), input validation plays a vital role in ensuring the integrity and reliability of the data processed by your application. By validating user input, you can prevent common security vulnerabilities, data inconsistencies, and potential errors. In this blog post, we will explore the importance of input validation in CAP and how it is controlled by annotations.

CAP provides built-in validation annotations that you can apply to entity properties or service parameters to enforce basic validation rule.

Lets have a look on the basic and essential validation annotations in CAP by examining a sample entity, "Student," and demonstrating how to apply various validation rules using annotations.

The code is available at GitHub.

Sample Entity: Student
Let's dive into the sample entity, "Student," and annotate its properties with input validation annotations:


entity Student : cuid, managed {
rollno : String(5) @mandatory @Core.Immutable @assert.unique;
name : String(50) @mandatory ;
age : Integer @assert.range: [ 18, 50 ];
dept : String(3) @assert.range enum { CSE; ECE; EEE; };
email : String(200) @mandatory;
telephone : String(132) @mandatory;
postCode : String(10) @mandatory;
}


annotate Student with {
name @assert.format: '/^[a-zA-Z]+ [a-zA-Z]+$/';
email @assert.format: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
telephone @assert.format: '^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$';
}

 


  • @mandatory




This annotation is used to specify that a property or field is mandatory, meaning it must have a non-null value.It also ensures that the property is required and must be provided when creating or modifying an entity instance. '*'  symbol is shown in the label of the property in UI Screen.If a mandatory property is not provided a value, the CAP framework will raise an error, indicating that the property is missing.


  • @assert.unique




This annotation is used to enforce uniqueness constraints on a property within an entity. It ensures that the values of the annotated property must be unique among all instances of the entity.

In the above example, the rollno property is annotated with @assert.unique. This means that each Student entity instance must have a unique value for the rollno property. When creating or updating a Student entity, the CAP framework automatically checks the uniqueness of the rollno value and raises an error if a duplicate value is detected.


  • @assert.range




This annotation  is used to define range constraints [min,max] on numeric or date/time properties within an entity. It ensures that the values of the annotated property fall within a specified range.

In the above example, the age property is annotated with @assert.range: [18, 50]. This specifies that the age property must have a value between 18 and 50, inclusive. When creating or updating a Student entity, the CAP framework automatically checks the range of the age value and raises an error if it falls outside the specified range.


  • @assert.range enum




If you want to enforce a specific range of values for an enum property in CAP, you can achieve this by combining @assert.range enum {values}

In the above example, the dept property is  annotated with @assert.range and defined as an enumeration. It ensures that the department value is within the specified options: CSE, ECE, and EEE.This ensures that only valid department values are allowed for the dept property.


  • @assert.format




This annotation is used to enforce a specific format or pattern on string properties within an entity. It allows you to validate that the value of the annotated property matches a particular format using a regular expression pattern.

In the above example, we have three properties (name, email, and telephone) annotated with @assert.format.

  • For the name property, the regular expression /^[a-zA-Z]+ [a-zA-Z]+$/ is specified as the format. This pattern enforces that the name value consists of two words separated by a space.

  • The email property is annotated with a regular expression pattern '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', which validates that the email value follows a standard email format.

  • The telephone property uses the regular expression pattern '^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$' to ensure the telephone value matches a specific phone number format.


It's important to note that the regular expressions used in @assert.format annotations should be carefully crafted to match the intended format and account for any variations or edge cases that may arise.

Error Handling:


Find the below output to showcase how the errors are handled when the validation fails.



These are  standard message raised by @assert annotation.These standard messages can be overridden based on the business purpose.

To override the standard messages in SAP Cloud Application Programming Model (CAP), you can create a messages.properties file and define custom messages for specific validation errors or other standard messages. Here's how you can set up the messages.properties file:

  1. Create a messages.properties file: In your CAP project, create a new file named messages.properties under the srv directory.

  2. Define custom messages:In the messages.properties file and add key-value pairs representing the messages you want to override. The keys should correspond to the standard messages you wish to replace.


For example, let's say you want to override the message for the assert.validation error. Add the following lines to the messages.properties file:
ASSERT_FORMAT=The input "{0}" contains invalid characters

ASSERT_RANGE=The input "{0}" should be between "{1}" and "{2}"

ASSERT_NOT_NULL={0} is mandatory input

ASSERT_ENUM=Please only enter a value from {{1}}

You can use placeholders in the messages.properties file to provide dynamic and more informative messages. Placeholders allow you to include dynamic values or parameters within the messages that can be replaced with actual values at runtime.

In the above example, we have defined messages with placeholders. The {0}, {1}, and {2} within the messages are placeholders that represent dynamic values.

When a validation error occurs, CAP will replace these placeholders with the actual values specified during runtime. For instance, if the assert.mandatory validation fails for the name field, the placeholder {0} will be replaced with the field name, resulting in a message like "'name' is mandatory input."

Similarly, for the assert.range validation, if the value of the age property falls outside the specified range, the placeholders {0}, {1}, and {2} will be replaced with the property name and the range values, resulting in a message like "The input 'age' should  be between 18 and 50."

Note: Ensure that the messages.properties file is placed in the correct location (srv directory) and that the file name is spelled correctly. Also, make sure that the custom messages in the file are in the format key=value, with one key-value pair per line.

This is how the standard messages are replaced through messages.properties.


 



Conclusion:


Input validation annotations in SAP Cloud Application Programming Model (CAP), provide a powerful mechanism to enforce validation rules . By leveraging these annotations, we can enhance the integrity and security of our application data. In this blog post, we explored a simple sample entity, "Student," and demonstrated the application of various input validation annotations to enforce mandatory fields, unique values, value ranges, and specific formats for properties such as email and telephone numbers.

Thank you for reading this blog and I hope you were able to follow it and be useful.

 
9 Comments
fioriexpert
Explorer
0 Kudos
Hi,

There is one more annotation added to rollno property i.e. Core.immutable. Can you please explain the significance of the same.
Thajunniza
Product and Topic Expert
Product and Topic Expert
0 Kudos
Hi Sagar,

@Core.immutable annotation is used to mark a property as immutable. It indicates that the value of the annotated property cannot be modified after it is initially set., the roll no property is annotated with Core.immutable,this means that once the roll no is set for a Student entity instance, it cannot be changed or updated. The property becomes read-only and retains its initial value throughout the lifecycle of the entity.And this field will be appeared in the create dialog while creation.



Regards,

Thaj
nkn30
Explorer
0 Kudos
Hi Thaj,

 

great Blog! The GitHub repository link takes me to a GitHub Enterprise Site. I don't think people outside the SAP Organisation can use this link.

 

 
elvisisik
Discoverer
0 Kudos

Hi @thajunniza14,

very helpful and important show case. I tried to reproduce the example without success. The messages.properties / messages_de.properties are placed in srv folder but it is no working.

Maybe I missed a specific point in the implementation which is not mentioned in the blog.
Could you plase move the git repo to a public git then may so I can review my code with yours

Best Regards,
Elvis

 

Thajunniza
Product and Topic Expert
Product and Topic Expert
0 Kudos

Sorry.As requested I have moved the code to below public repo.

GitHub

Thajunniza
Product and Topic Expert
Product and Topic Expert
Sorry.As requested I have moved the code to below public repo.

GitHub

 
Ben
Participant
0 Kudos

Thank you @Thajunniza for sharing this helpful piece of information. There is also a little bit of information in CAP documentation here 

In order to use it in my project (CAP v. 7.6) I adjusted the package.json like this:

 

"cds": {
    "i18n": {
      "default_language": "de",
      "folders": ["i18n"]
    },
...
}

 

The properties file I am using is located in srv/i18n/messages_de.properties.

I was interested what other TEXTs can be customized and I believe I found the original properties file containing all tests. It is located in 

node_modules/@sap/libx/_runtime/i18n/messages.properties:
 
400=Bad Request
401=Unauthorized
403=Forbidden
404=Not Found
405=Method Not Allowed
406=Not Acceptable
407=Proxy Authentication Required
408=Request Timeout
409=Conflict
410=Gone
411=Length Required
412=Precondition Failed
413=Payload Too Large
414=URI Too Long
415=Unsupported Media Type
416=Range Not Satisfiable
417=Expectation Failed
424=Failed Dependency
428=Precondition Required
429=Too Many Requests
431=Request Header Fields Too Large
451=Unavailable For Legal Reasons
500=Internal Server Error
501=The server does not support the functionality required to fulfill the request
502=Bad Gateway
503=Service Unavailable
504=Gateway Timeout

MULTIPLE_ERRORS=Multiple errors occurred. Please see the details for more information.

# -------------------------------------------------------------------------------------------------
# all texts below are subject to change!
# -------------------------------------------------------------------------------------------------

# fragments
ENTITY=entity
TYPE=type
FUNCTION=function
ACTION=action

# assert
ASSERT_VALID_ELEMENT=Element is not valid
ASSERT_RANGE=Value {0} is not in specified range [{1}, {2}]
ASSERT_FORMAT=Value "{0}" is not in specified format "{1}"
ASSERT_DATA_TYPE=Value {0} is invalid according to type definition "{1}"
ASSERT_ENUM=Value {0} is invalid according to enum declaration {{1}}
ASSERT_NOT_NULL=Value is required
ASSERT_TARGET="Value doesn't exist"

# db
NO_DATABASE_CONNECTION=No database connection
ENTITY_ALREADY_EXISTS=Entity already exists
ENTITY_LOCKED=Entity locked
UNIQUE_CONSTRAINT_VIOLATION=Unique constraint violation
FK_CONSTRAINT_VIOLATION=Foreign key constraint violation

# remote
INVALID_CONTENT_TYPE_ONLY_JSON=Invalid content type. Only "application/json" is supported.

# access control
INSERTABLE=insertable
READABLE=readable
UPDATABLE=updatable
DELETABLE=deletable
ENTITY_IS_INSERT_ONLY=Entity "{0}" is insert-only
ENTITY_IS_READ_ONLY=Entity "{0}" is read-only
ENTITY_IS_NOT_CRUD=Entity "{0}" is not {1}
ENTITY_IS_NOT_CRUD_VIA_NAVIGATION=Entity "{0}" is not {1} via navigation "{2}"
ENTITY_IS_AUTOEXPOSED=Entity "{0}" is not explicitly exposed as part of the service
EXPAND_IS_RESTRICTED=Navigation property "{0}" is not allowed for expand operation

# rest protocol adapter
INVALID_RESOURCE="{0}" is not a valid resource
INVALID_PARAMETER="{0}" is not a valid parameter
INVALID_PARAMETER_VALUE_TYPE=Parameter value for "{0}" must be of type "{1}"
INVALID_OPERATION_FOR_ENTITY=Entity "{0}" has no {1} "{2}"
NO_MATCHING_RESOURCE=The server has not found a resource matching the requested URI
INVALID_POST=POST is only allowed on resource collections and actions
INVALID_PUT=PUT is only allowed on a specific resource
INVALID_PATCH=PATCH is only allowed on a specific resource
INVALID_DELETE=DELETE is only supported on a specific resource
CRUD_VIA_NAVIGATION_NOT_SUPPORTED=CRUD via navigations is not yet supported

# OData protocol adapter
BATCH_TOO_MANY_REQ=Batch request contains too many requests

# draft
DRAFT_ALREADY_EXISTS=A draft for this entity already exists
DRAFT_NOT_EXISTING=No draft for this entity exists
DRAFT_LOCKED_BY_ANOTHER_USER=The entity is locked by user "{0}"
DRAFT_MODIFICATION_ONLY_VIA_ROOT=A draft can only be modified via its root entity
DRAFT_ACTIVE_DELETE_FORBIDDEN_DRAFT_EXISTS=Entity cannot be deleted because a draft exists

# singleton
SINGLETON_NOT_NULLABLE=The singleton entity is not nullable
KomalM
Explorer
0 Kudos

@Thajunniza Thank you for detailed explaination. I've tried this approach and it worked for main entity but not working for any of my assoicated entites. Can you please help me to understand how this approach will work with Association and Composition?

Here is code for example:

entity Student : cuid, managed {
    rollno    : String(5)   @mandatory  @Core.Immutable @assert.unique;
    name      : String(50)  @mandatory ;
    email     : String(200) @mandatory;
}

annotate Student with {
    name      @assert.format: '/^[a-zA-Z]+ [a-zA-Z]+$/';
    email     @assert.format: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
}

entity Scorecard : cuid, managed {
    student   : Association to Student;
    details   : String(100);
    marks     : Integer;
    grade     : String(3);
}

annotate Scorecard with {
    @error.mandatory: 'Scorecard.marks.mandatory'
    marks;

    @error.mandatory: 'Scorecard.grade.mandatory'
    grade;
}
shf
Explorer
0 Kudos

Hello guys,

is it possible in CAP to create custom validation rules in combination with custom annotation based validations to check user input, e.g. if a field should be validated that the given value has a certain length and consists only of upper case values, a custom message like e.g. "Input should contain upper case letters only with length of 3 characters" ? 

As far as I have understood, the CAP standard provides simple validation rules only or is there a validation API I can use for this purpose?

Thanks,

Stephan