When building your application with the SAP Cloud Application Programming Model you can make use of actions and functions. A question that often comes up is when you should use these and what their benefit is. In this blog I want to share my perspective and why I consider them an important element in application development.
Simply put, actions and functions in CAP are like methods in object-oriented programming. Actions have side-effects on application state, whereas functions are pure and free of side-effects. Like methods, both actions and functions can have parameters and a return value. Functions are required to have a return value, for actions this is optional.
A further differentiation is that of bound vs. unbound. Staying in the OO metaphor bound actions and bound functions are instance methods, unbound actions and unbound functions are static methods.
Let’s look at a variation of the bookshop example to illustrate the ideas and start with an excerpt from the data model, that contains a publication status of a book. Please note that publicationStatus is a read-only element.
entity Book : managed {
key ID : UUID;
title : String;
summary : String;
@readonly
publicationStatus: String enum {
UNPUBLISHED;
PUBLISHED;
DELISTED;
} default 'UNPUBLISHED';
}
On top there are two services: A maintenance service for maintaining the book catalog, and a book selling service that allows consumers to buy books. Let’s first have a look at the book maintenance service:
service BookMaintenanceService {
entity Book as projection on samples.Book actions {
action publish();
action delist();
};
action applyDiscount(percentage: Decimal, validFrom: Date, validTo: Date);
}
There are two bound actions on a book: publish and delist. The action implementation (not shown here) will set the publication status on a book, which is not changeable directly being annotated with @readonly. The third action applyDiscount is an unbound action that will set a discount on all books within a certain timeframe.
The book selling service contains a bound action addToShoppingCart on the book that obviously adds the book to a consumer shopping cart. The bound function calculateDeliveryDate determines the delivery date of a book given the country and address.
service BookSellingService {
entity Book as projection on samples.Book actions {
action addToShoppingCart();
function calculateDeliveryDate(country: Country, address: String) returns Date;
}
}
Actions and functions are a concept of OData that has been adopted by CDS and CAP. Consequently, actions and functions are exposed by CAP using the OData protocol. This cheat sheet summarizes nicely how in OData actions and functions can be called. You can also call actions and functions programmatically on CAP services, in both CAP Node.js and CAP Java.
Actions and functions are nicely integrated into Fiori Elements and can be declaratively put on object pages and list reports where they will simply become buttons for users.
In my experience you should consider using actions in the following situations:
@requires: 'Publisher' action publish();
If you are working with domain-driven design (DDD) there is a straight-forward translation: each command in your model that is different from create, update and delete is a good candidate to become an own action in your CAP service. With appropriate actions, you can also emit according DDD domain events much easier.
Good real-world candidates for actions are any kind of status transitions, controlled change of active contractual entities like employments, service contracts with customers and any kind of bulk changes that affect many entities.
Functions are the side-effect-free, read-only siblings of actions. I personally consider them useful in the following situations:
Good real-world examples for functions would be tax and price calculations and any form of optimization algorithm.
I'm convinced that actions and functions are a great way of enriching CDS services - that have the tendency to become CRUD centric - with more business semantics. They help turning an “anemic” service (along the lines of the anemic domain model described by Martin Fowler) into an expressive, semantically rich service.
Hopefully this blog was useful to you and helps you deciding in which situations to use actions and functions in CAP.
What are your experiences with actions and functions and your indications to use them? Let me know in the comments below or on other channels!
For being notified about my future blogs, please subscribe to ulrich.bestfleisch.
You might also want to check out my previous blog on establishing domain services in CAP.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
20 | |
9 | |
9 | |
7 | |
7 | |
7 | |
7 | |
6 | |
5 | |
5 |