SAP Tutorial: The Complete CAP Java Part 8

Brian Heise
6 min readAug 12, 2021

--

Custom Actions and Input Type Definitions

Photo by Christopher Gower on Unsplash

Contents

Welcome to Part 8 of the Complete CAP Java tutorial series! In this series I’m teaching step by step how to rebuild SAP’s CAP Java sample application, an app for running an online bookshop. Up to now we’ve been implementing the customer-facing Browse Books application (code can be found here). This is what we’ve made so far:

Our progress so far

And here is are target. In the red box is the feature we’re currently building, a button to allow us to add a review:

Our target application (our current goal marked in red)

Last time we defined our Reviews model using CDS and made some mock data. Be sure to check it out if you need a refresher. Today we’re going to define a custom action in CDS that we will use to create our Reviews. Today is just the CDS definition for the function — next week we’ll implement the logic using Java.

Step 1: Defining a Custom Action

One of the features of Fiori Elements that can be a little frustrating at first is how to trigger some kind of event on the page. After all, we can’t write any logic directly in the Fiori Elements application, so our hands feel like their tied.

However, Fiori Elements is controlled entirely by oData and oData luckily has the perfect feature: custom actions and custom functions. oData borrows this terminology from functional programming, so for those new to that style a function is simply a subroutine that has no side-effects — in the case of oData, that would mean no writes to the database. An action on the other hand does include side effects. Again, in oData’s case a side effect would typically just be a write to the database (see this oData blog article for more information). For a more tangible example, imagine we wanted to get just a count of how many books are in the database and nothing else — that would be a function because it requires only reading. However, we want to actually write a new Review to the database, so we’re going to create an action. Let’s learn how to do that using CDS.

To begin with, we need to understand that CDS allows us to define two different types of actions and functions: bound and unbound. The bound variety is attached to a specific entity, ensuring that the entity is present in the context of any call to it. The unbound variety can be called without any specific entity context (see this documentation for more info). In our case the former is what we want because we need to attach our new Review to a specific Book. Let’s get to the code.

First let’s open up our srv/cat-service.cds file to refresh ourselves on our current service definition.

srv/cat-service.cds

We wanted to bind our action to our Books entity. Define a list of available actions bound to this entity in the following way. Note that the newline and tab are for readability — they aren’t required.

Defining a list of bound actions on the Books entity

Next we define our action. First we start the definition with the action keyword followed by a name for the action. Next is a comma-separated list of inputs for the function, each with a required type. Finally, we provide the return type, which we are defining as an instance of the Reviews entity. Note that we aren’t limited to returning just entities like Reviews — we could return a custom type as well.

Definition for the addReview action

Let’s compile our service definition using cds compile --to edmx to see the effect of our work. This is what will be sent to our Fiori Elements app to tell it how to process our action.

addReview action compiled to edmx

Nice work! However, this definition has some weaknesses. We’ll discuss those in the next section and show you how to remedy them.

Step 2: Custom Input Type Definitions

The weakness of our function definition is that it that its input types are too generic. We know from Part 7, for example, that we defined our our rating field as an enum type that only accepts values of 0–5, but an integer could be any non-decimal positive or negative number. Leaving it like this would require some manual validations in the Java handler that we will make for this action later. Instead, though, we can simply reuse the type to the same one we defined before, which is useful because if we update that type definition we won’t need to update the Java code as well. We can do so in the following way:

Accessing rating through the bookshop namespace.

At this point, though, we can see some other issues as well. Recall that when we created our Review model, we specified a max-length for the title and text fields as 100 and 1000 characters respectively:

db/reviews.cds

If we don’t also define that here, then users might submit text that’s too long, again requiring us to do manual validation. We could solve the issue as follows:

Character limits to input types

I think you can already see the problem here, though — what if we decided to change the length for these fields? Then we’d have to update the code in two places, which would be a hassle and easy to forget. Instead, let’s define some custom types to handle this for us. In the db folder, let’s create two new files, name.cds and text.cds, and give them the following content:

Our custom Text and Name types

Now we can simply use these in our Rating entity definition and in our action definition:

Reviews entity with custom Title and Text types
addReview action with custom Title and Text types

Let’s not stop there, though! If we look again at our Books entity we’ll see that it’s title and descr fields are also 100 and 1000 characters respectively. We can reuse our types there. Not only that, genre and author also have a length of 100, so we can reuse our Name type there are well.

Books entity updated with custom Name and Text types

Finally, our db folder is getting a little cluttered with our Type and Entity definitions all mixed together. I’m going to separate them into different folders for organizational purposes. Be sure to update your index.cds file if you decide to do this too.

Now that’s nice and organized!

Conclusion

Today we used CDS to define our custom action and used CDS type definitions to make sure it’s inputs will properly match the entities that they will be used to create. Next week we’re going to make a handler for this action using Java so that we can define the logic needed to create the Review and attach it to its respective Book. See you then!

Was anything unclear in this tutorial? Leave a question below and I’ll get back to you as soon as possible. Was anything incorrect? Please leave a comment below and let me know (a source for the correction would be most helpful). Thanks for your comments!

Support

Did you like this blog? Want to make sure I can keep creating them? Then consider subscribing on Patreon!

--

--

Brian Heise
Brian Heise

Written by Brian Heise

Full Stack web developer employed at Liferay Japan

Responses (1)