While developing enterprise ready cloud applications using Cloud Application Application programming model (CAP), you can define / model custom operations specific to business entity or process via functions or actions in addition to CRUD operations.
- Actions are used for operations, which add or modify data via POST request.
- Functions are used to only retrieve data via GET request.
Both actions and functions can be bound which means this custom operation is connected to a business entity or unbound which means this operation can be on one or more entities. More information can be found here.
In most cases, You will have a fixed structure/type input or output for custom operations. However in very few cases you might have an operation where input or output changes time to time. In this blog post, i will show how you can define such an action or function which takes input and provides output with dynamic type.
CAP currently support 3 protocols i.e. OData V4, Rest, GraphQL. Out of these 3 protocols, only in Rest protocol based services you can define functions and actions with dynamic input and/or output.
Let’s look at an example:
Service Definiation:
@protocol: 'rest'
service RootService {
@open
type object {};
action MyAction(input : object) returns object;
function MyFunction(category : Integer) returns object;
}
By annotating the service with @protocol: ‘rest’, the service becomes rest compliant. In above example, cds type “object” is annotated with @open to indicate that the structure or type is unknown. Then it is used in both MyAction and MyFunction operations.
Service Implementation
const cds = require("@sap/cds");
module.exports = cds.service.impl(async function (srv) {
srv.on('MyAction', async(req)=>{
req.data["AdditionalField"] = "AdditionalFieldValue";
return req.data;
}),
srv.on('MyFunction', async(req)=>{
let result = {};
if(req.data.category === 1){
result.category = 'Category 1';
result.field1 = "Random Field Value";
result.field2 = [{"f1":"f1 Value1"}]
}else{
result.category = {"Info":"Category2"};
result.field1 = "Random Field Value";
result.field2 = [{"f1":"f1 Value1"}, {"f1":"f1 Value2", "f2":"f2 Value2"}];
}
return result;
})
});
In the implementation of MyAction operation, an additional field is added with the incoming data. Simillarly the result of MyFunction operation is different based on the input category. Both of these implementations are coded just to indicate that the resultant structres are dynamic.
Testing the above code and its corresponding responses.
Operation | Request/Response |
MyAction | Request:
Response:
|
MyAction | Request:
Response:
|
MyFunction | Request:
Response:
|
MyFunction | Request:
Response:
|
Note that this is currently possible in CAP services with Rest Protocol only. Hope this feature will be added for other protocols as well.
More information aboue cloud application programming model can be found here. You can follow my profile to get notification of the next blog post on CAP. Please feel free to provide any feedback you have in the comments section below and ask your questions about the topic in sap community using this link.