XXX 2026
Preview Release Notes
This is a preview of the release notes for our upcoming release. These notes share what you can expect soon. Note that these notes are work in progress, not official yet, and might still change.
Event Queues Scheduling Beta
Efficient Leftover Processing
We write "markers" to t0 such that we can recover more efficiently if event processing is disrupted.
- Requires
@sap/cds-mtxs^3.9❗️ - For Node.js, enable via:
cds.requires.scheduling: true. UseslegacyLocking: false, which is not the default in cds^9. Hence the opt-in.cds.requires.scheduling: truewill become the default in cds^10.
Scheduling API
Schedule and cancel "named tasks" via new APIs:
- Java: ...
- Node.js: ...
CDS Language & Compiler
Node.js
Important Change ❗️
N/o Draft Requests
( read this heading as: "Not only Draft Requests" )
We consolidated and simplified the ways to work with active data, that is, active instances of @odata.draft.enabled entities. In particular for non-Fiori clients, that know nothing about the concept of Fiori Drafts at all.
Add IsActiveEntity=true as a key parameter to your requests to address active data:
POST /Books { IsActiveEntity:true, ... } //> CREATE
PATCH /Books(ID=201,IsActiveEntity=true) {...} //> UPDATE
DELETE /Books(ID=201,IsActiveEntity=true) //> DELETE
GET /Books(ID=201,IsActiveEntity=true) //> READ2
3
4
Compare with draft requests ...
Conversely, add IsActiveEntity=false to specificly address draft data:
POST /Books { IsActiveEntity:false, ... } //> NEW
POST /Books(ID=201,IsActiveEntity=true)/draftEdit //> EDIT
POST /Books(ID=201,IsActiveEntity=false)/draftActivate //> SAVE
PATCH /Books(ID=201,IsActiveEntity=false) {...} //> PATCH
DELETE /Books(ID=201,IsActiveEntity=false) //> DISCARD
GET /Books(ID=201,IsActiveEntity=false) //> READ2
3
4
5
6
Now also for Node.js
This was in place for CAP Java since long, now also for CAP Node.js. Without any extra configs like cds.fiori.bypass_draft, or cds.fiori.direct_crud. These are no longer required and can be removed.
Going one step further we assume IsActiveEntity=true by default. So, the following requests would also always refer to active data, equivalent to the ones above:
POST /Books {...} //> only with `cds.fiori.draft_new_action`
PATCH /Books/201 {...}
DELETE /Books/201
GET /Books/2012
3
4
Only with cds.fiori.draft_new_action: true.
All of the above was possible without any conflict, and without any changes required, except for line 1 above. This depicts a changed behavior, as such POST requests created new drafts in the past, but would create active instances instead from now on.
To achieve this, we introduce a draftNew action to create drafts – similar to draftEdit and draftActivate for editing and saving drafts –, which are:
- automatically added to models by the compiler, and served by CAP runtimes
- vended to OData clients through
@Common.DraftRoot.NewActionannotation - and hence used automatically by Fiori clients.
In total, this leaves us with the following options to create new drafts and active entities (with new and gone options highlighted in green and red):
POST /Books(201)/draftEdit // creates a draft for editing an existing book
POST /Books/draftNew // creates a draft for a new book
POST /Books {...} // created a draft for a new book
POST /Books {...} // creates a new active book now
POST /Books {IsActiveEntity:true...} // creates a new active book
POST /Books {IsActiveEntity:false...} // creates a draft for a new bookUnfortunately, two limitations disallow to fully enable that by default, right now:
- Existing clients, or tests, relying on
POSTrequests to create new drafts as before. - A bug in Fiori elements in combination with Fiori Tree Views.
So, to avoid any breaking changes, we introduced a the cds.fiori.draft_new_action option. Switch it on if neither of the above limitations apply in your project.
Only for Node.js
Taken strictly, queries like above violate the OData specification: As IsActiveEntity is a key property in draft-enabled entities, spec-compliant servers are expected to reject single-instance requests that don't include that parameter.
For Node.js we took the freedom to relax in that regard, but we didn't have that luxury in Java, as we are (still) bound by the overly spec-compliant Olingo library there.
Draft locks are taken account of in all relevant cases: If a draft exists for a given instance, direct updates and deletes, as well as conflicting attempts to edit the entitiy are rejected.
Key Benefits
The simplified approach to address active data is not only less clumsy to use, it also unblocks technical API clients, including AI use cases, that don't know anything about Fiori Drafts at all, as well as functionality like SAP Fiori Elements Mass Edit, which relies on direct modification of active entities via PATCH requests. No changes are required to existing projects, and no breaking change in behaviour by default.
Learn more about Fiori Draft support in CAP.
Restrictions on $expand
// TODO: promote?
Support added for restricting $expand via:
@Capabilities.ExpandRestrictions.MaxLevels: <number>@Capabilities.ExpandRestrictions.Expandable: falsecds.query.restrictions.expand.maxLevels: <number>(default:null) //> TODO: adjust to final config name
Learn more about these restrictions in the Security guide.
Java
Important Change ❗️
Default Value for cds.Date
Make use of $now to define the current day as default value for elements of type Date:
entity Approvals {
dayOfApproval: Date default $now;
}When you create the entity, the system populates dayOfApproval with the day derived from the current timestamp ($now) relative to the UTC timezone.