July 2020
Welcome to the release of CAP. Find the most noteworthy news and changes in the following sections.Important News and Changes❗️
Streamlined Compiler Switched on by Default
The streamlined compiler implementation is switched on by default. Learn more in the Compiler section below
Refactored Node.js Runtime --- Version 4
Behind the scenes of stable APIs the Node.js runtime implementation has been improved and refactored substantially.
Learn more in the Node.js section below
CLI Commands moved to @sap/cds-dk
To minimize the footprint of the Node.js runtime, close to all CLI commands have been moved out of @sap/cds and into @sap/cds-dk now.
Learn more in the CLI section below
OData V2 Officially Supported
From now on, CAP officially supports OData V2 and SAP Fiori Elements UIs based on V2. In the beginning, we use the OData V2 proxy, which we'll integrate intrinsically in the long run to reduce TCO.
Find details in the Serving UIs guide
SAP HANA Cloud Edition Supported Out-of-the-Box
Already since May, CAP provides out-of-the-box support for SAP HANA Cloud Edition. No changes are required to models or code, only a single configuration is to be added → see details in the Databases guide.
New and Revised Guides
- About CAP → received another major overhaul
- Features Overview → adjusted to latest additions
- Cookbook > Authorization and Access Control
- Java > Event Handlers
- Java > Application Services > Result Builder
- CDS > Node.js APIs has been moved here from Node.js reference docs
- Cookbook > Extensibility has been moved here from Advanced
Command Line / Toolkit
CLI Commands Moved to @sap/cds-dk❗️
As already started with the introduction of @sap/cds-dk in 2019, we now moved all CLI commands to the -dk packages, except for run and serve, which are used to launch Node.js runtime servers.
Background: We want to drastically strip down runtimes to minimum footprint.
If you already followed the recommendations to install cds-dk globally and use that in your setups accordingly, this shouldn't affect you at all. Yet, in case you didn't, ensure to follow these steps to avoid pitfalls:
In Java projects, use the new cds-maven-plugin; no other changes are necessary, as this plugin uses
@sap/cds-dkout of the box.In Node.js projects with existing mta.yaml files, replace all occurrences of
npx cdswithnpx -p @sap/cds-dk cdsin those files.In freestyle CI setups, either (A) install
cds-dkprior to the execution of build commands, that isnpm i @sap/cds-dk && npm run ..., or (B) add a dev dependency to your project, for example:npm i @sap/cds-dk --save-dev.
Note: (B) increases the installation time for everynpm installcall for every developer, so rather prefer option (A).
Streamlined and Modularized cds build
Builds for Node.js and SAP HANA have been optimized for better performance. In addition, we renovated our build infrastructure to allow flexible customization using respective CLI options.
For example:
# choose specific build task cds build --for hana # override task-specific options/defaults: cds build --for hana --opts model=[db,srv,schema.cds] # build with production profile: cds build --production # ...which is a shell-independent equivalent to: NODE_ENV=production cds build # Learn more with: cds build --help
See also how database configuration uses profiles.Learn more about Node.js configuration in general.
Deprecated/Obsolete
cds build/all→ simply usecds buildinstead.cds build --clean→ is the default now.
Using await in cds repl
We now support using await directly on cds repl prompt inputs. For example:
[demo] cds repl
Welcome to cds repl v4.1.5
> m = await cds.load('*')
This feature is provided through Node.js --experimental-repl-await option.
CDS Editors & Tools
The following features are available for all editors based on our language server implementation for CDS in SAP Business Application Studio, Visual Studio Code, and Eclipse. The plugin for Eclipse is available for download at https://tools.hana.ondemand.com.
We Are on VS Code Marketplace --- Finally
Finally, the VS Code extension for the core data services (CDS) language can be installed now from the Visual Studio Marketplace. See Getting Started > Tools for more details. If the extension is already installed and enabled in VS Code, it will be updated automatically.

Welcome Page in VS Code

The VS Code extension now comes with a welcome page, which shows latest information about CAP. It starts automatically once whenever an update arrives for the extension. Later, you can open the page through the command CDS: Show CAP Release Notes.
Issue Reporting in VS Code

You can now ask questions or report issues directly from VS Code. Just open the Report Issue dialog, select the VS Code extension, and follow the link to SAP Q&A. Give us as much information as possible in the pre-filled SAP Q&A form to enable better processing of your report.
Editor Support for doc comments (/** ... */)
Hovering over a definition now displays doc comments, if available:

As well as details for code completion:

Use the doc... snippet to create a doc comment. You can use markdown to structure a doc comment. Formatting also beautifies doc comments.

An information hint informs you about deprecation of the @cds.doc annotation. A quick fix allows you to convert a @cds.doc annotation into a doc comment.

You can specify the maximum line length of doc comments using the command CDS: Show Formatting Option Configuration. On the Other tab, edit the option Max doc comment line length.

For better visibility doc comments are highlighted differently than standard block comments.
QuickFix to Generate using Statements
You can now type an existing artifact name that isn't yet imported (through a using statement). A quick fix for the error marker suggests possible artifacts from the workspace. Select the corresponding one to generate the using statement. The new import is inserted or merged among existing using statements, sorted alphabetically. The using statement is formatted.

More CDS Editor Improvements
Semantic Code Completion --- Code completion now also suggests identifiers for elements, enums, actions, and parameters in
annotateandextendwithinannotateandextendstatements.Syntax highlighting for identifiers --- Until now identifiers, including variants delimited with
\![...], haven't been classified so themes couldn't color them.Related Info in Messages:

CDS Language & Compiler
Streamlined Compiler by Default ❗️
The already mentioned streamlined compiler implementation is now used by default. This new implementation brings significantly improved performance in compilation and bootstrapping servers, as well as reduced memory consumption at runtime.
In the unlikely case that the new default causes problems in your project, you can switch back as follows in your package.json or .cdsrc.json:
"cds": {
"features": { "snapi": false }
}Note: This fallback option will be offered only for a limited grace period. Make sure to switch to snapi as soon as possible.
Managed Compositions for Improved Domain Modeling
We deliver a major improvement to keep your domain models concise and comprehensible. Use Managed Compositions to nicely reflect document structures, without the need for separate entities, reverse associations, and unmanaged on conditions. For example:
entity Orders { ...
Items : Composition of many { ...
product : Association to Products;
quantity : Integer;
}
}Managed Compositions are especially handy for many-to-many relationships:
entity Teams { ...
members : Composition of many { key user: Association to Users; }
}
entity Users { ... }And here's an example of an attributed many-to-many relationship:
entity Teams { ...
members : Composition of many {
key user : Association to Users;
role : String enum { Lead; Member; Collaborator; }
}
}
entity Users { ... }Learn more in the CDS Reference Documentations
IMPORTANT: CSN not stable yet. --- Means: While you can safely use Managed Compositions as shown above, don't rely on the current CSN output of for example,
cds compilefor managed compositions, as that may change.
Arrayed Elements in Entities to Avoid Joins
You can now declare arrayed elements in entities using keywords many or array of:
entity User { ...
emails: many { kind:String; address:String }
}Arrayed elements are stored as JSON-stringified values in single NCLOB columns in relational tables. Node.js runtime already supports this generically; Java will follow.
Performance Benefits --- On the one hand, this removes a lot of clutter from your models. On the other hand, and even more important, it greatly improves performance during data access. This results from eliminating a lot of joins to separate entities.
See also: Feature MatrixSee also: Avoid Overly Normalized Models in the Domain Modeling GuideLearn more in the CDS Reference Documentations
Structs and Associations in on Conditions
We now allow comparing struct elements and managed(!) associations in on conditions of other associations. Have a look at the following example, which is only possible since this release:
entity Project { ...
teams : Association to many Teams
on teams.country = $self.country
and teams.validity = $self.validity;
country : Association to Country;
validity : Validity;
}
entity Teams { ...
country : Association to Country;
validity : Validity;
}
type Validity : { _from:Date; to:Date }Both operands must be structurally compatible, that is both structures must be expandable to an identical set of leaf paths. Each leaf path must terminate on a builtin CDS scalar type. The original relational term of the form
s1 op s2is replaced by the resulting expressions1.leafpath_0 op s2.leafpath_0 (AND s1.leafpath_i op s2.leafpath_i)*with i < n leaf paths.
Enhanced Projection Clauses
You likely noticed already that as projection on and as select from are mostly interchangeable alternatives, however the former should be preferred over the latter whenever you don't need the full power of SQL.
This is especially true when defining projections on entities from remote services in service consumption scenarios. However, while in the past the following clauses weren't allowed, they're now:
wherehavinggroup byorder bylimit
For example, provided content of these clauses will be translated to respective query options in OData in Service Consumption Scenarios.
Learn more in the CDS Reference Documentations
Not Null for Parameters and Return Types
Parameters and return types can now also be declared to be (not) null.
Node.js Runtime Version 4 ❗️
Behind the scenes of given APIs this release provides a broad range of major improvements. We removed inconsistencies, closed gaps and fixed several little glitches. In effect, release 4 is the basis for us to add new features and qualities faster than before, and at the same time gives you more stable and more future-proof APIs.
While public, documented APIs weren't affected, you might nevertheless have written code, which relied on internal interfaces and behaviors, which you should correct accordingly. → see Important Changes below.
We strongly recommend doing so, and to upgrade as soon as possible, as former releases will receive only critical bug fixes from now on.
Important Changes ❗️
The following changes mostly affect undocumented, internal interfaces.
Eliminated Promise Voodoo : Former versions did quite some magic, meant to ease Promise Hell. With broad availability of async/await this became useless overhead, removed in release 4. Now, always call cds.connect.to with await:
const srv = await cds.connect.to('some-service')Eliminated next() Voodoo : Before, the framework called next() implicitly if an .on handler returned undefined. Now, always call next() explicitly, either with await, or with return:
this.on(..., async (req,next)=>{ /* ... */ await next(); /* ... */ })
this.on(..., (req,next)=>{ /* ... */ return next() })See revised docs for .on handlers
Fallback: Set config
cds.features.implicit_next:trueto restore former behavior, but correct your handlers, as soon as possible.
Deprecated and Removed
req.user.has(<roles>)→ usereq.user.is(<role>)insteadreq.user.<attr>→ usereq.user.attr.<attr>insteadin-process-messagingkind → in-process messaging is always enabled.db.run(()=>{})→ usecds.run([...multiple queries])instead.- init.js variant
(db)=>{...}→ usedb.run([...multiple queries])instead. - cds.ql
.where('x',1)or.where('x','=',1)→ use documented variants only
Important Fixes
$user.<attr>===undefinederroneously evaluated totrue→ now it'sfalse$metadatarequests erroneously got authorization-checked → not anymore@restrictdid permit all operations not mentioned, for example, the following annotation allowed all other operations, like UPDATE or DELETE, for every user:
@restrict:[ {grant:'READ',to:'some-role'} ]GET /Foo(1)/barerroneously translated to semi joins → now correctly yields:
{SELECT:{from:{ref:[ { id:'Foo', where:[{val:1}] }, 'bar' ]}}Refactored and Enhanced Core Services API
These enhancements are the main effects of the refactorings. They close many API gaps and glitches, and provides us with a clean core, for the things to come...
Classes cds.Service, cds.Request, and cds.Event
cds.Serviceis the common base class for all connected or provided services.- Instances of
cds.Requestrepresent synchronous requests. - Instances of
cds.Eventrepresent asynchronous event messages.
New Service and Request Methods
cds.emitfor both, synchronous requests, and asynchronous event messages.req.warn,info,notifyallow to return messages with different severity- HTTP-style convenience methods complementing the CRUD-style ones.
Learn more about the refactored Core Services APIs
Streamlined, Extensible Bootstrapping by cds.server
The bootstrapping process has been greatly optimized, in particular by loading only one consolidated effective model, instead of many per service independently. In effect, both, bootstrapping times, as well as memory consumption improve by magnitudes, especially with larger projects.
In addition, the built-in server.js implementation has been redesigned, and allows to plug-in custom logic, without loosing the convenience of cds watch et al:
// custom server.js
const cds = require('@sap/cds')
cds.on('bootstrap', (app)=>{ /* add your own middleware */ })
cds.on('served', ()=>{ /* add more middleware */ })
module.exports = cds.server //> delegate to default server.jsLearn more about cds.server-based bootstrapping
IMPORTANT: In case you're using own
server.jsimplementations, we strongly recommend revisiting these and considering refactoring them to extend the built-in one, as documented in customserver.js. This ensures you benefit from the mentioned and future optimizations.
Custom cds.Service Subclasses
Besides providing impl functions, service implementations can now provide specific subclasses of cds.Service, as shown below:
// srv/cat-service.js
const cds = require('@sap/cds')
class CatalogService extends cds.ApplicationService {
async init(){
this.on ('UPDATE','Books', (req)=>{...})
await super.init()
this.before ('CREATE','Books', (req)=>{...})
}
}
module.exports = CatalogServiceCommon Service Factory : This is one of many more effects of the new service factory, commonly used by cds.serve and cds.connect now. This applies the same consistent ways to register new implementations via cds.requires options, model annotations @impl and @kind, or the well-known .cds/.js sibling files mechanism.
Learn more about new ways of Providing Service ImplementationsLearn more about new ways of Configuring Required Services
Custom Handlers on cds.connected Services
As a CAP Node.js developer, you're used to add event handlers to provided services to add custom-specific implementations to the service. Starting with this release, you can also do the same from the consumer side to services you connected to, such as Database Services or Remote Services:
const db = await cds.connect('db')
db.prepend (()=>{
db.on ('INSERT','Orders', req => {...})
db.after ('READ','*', each => {...})
})Learn more about Adding Handlers to cds.connected Services
For example, you could use that to fix gaps in our generic support, by providing your own generic handlers to our built-in database services for SQLite and HANA.
With this, we make these statements in the About CAP page even more true:
- Every active thing in CAP is a service, that is a
cds.Service, and... - Everything happens in response to events, that is in Event Handlers.
All service implementations essentially are just a bunch of registered event handlers. There's actually no difference between handlers added from provider side, or from consumer side. There's also no difference between the handlers we add to provide all the generic framework features of CAP, or the handlers you add. At the end of the day, we all eat the same dog food --- with this release more than ever before.
Custom and Dummy Authentication Strategies
New Dummy Authentication Strategy : The dummy strategy creates a dummy user that passes all authorization checks. It's meant for temporarily disabling the @requires and @restrict annotations at development time.
Custom Authentication Middleware : In case the supported authentication strategies don't fulfill the necessary requirements, developers can provide a custom express middleware for authentication.
Learn more about the revamped Authentication framework
INSERT Queries Return Generated Keys
INSERT queries now return iterables, similar to results from SELECT queries, which allow to reflect on (generated) keys of the inserted entities, as shown in this snippet.
const [ Emily, Charlotte ] = await INSERT.into (Authors,[
{name:'Emily Brontë'},
{name:'Charlotte Brontë'},
])
INSERT.into(Books).columns('title','author_ID').rows(
[ 'Wuthering Heights', Emily.ID ],
[ 'Jayne Eyre', Charlotte.ID ],
)Find details in the updated API docs of cds.run
Generic Support for Arrayed Elements
See Arrayed Elements in the CDS Language section
Localized Messages / i18n
Application developers can now use localized error messages. For example:
# i18n/messages_en.properties
ORDER_EXCEEDS_STOCK=The order of {0} books exceeds the stock by {1}req.reject( 400, 'ORDER_EXCEEDS_STOCK', [
order.quantity,
order.quantity - book.stock
])Learn more about Localized Messages
Miscellaneous
New
srv.after('each', row => ...)— the former technique to register per-row handlerssrv.after('READ', each => ...)broke when code was minified. The new method using pseudo event'each'is minifier-safe.New
srv.prepend(srv => ...)— usesrv.prepend(...)to register event handlers to be executed before the already registered handlers. For example, extensions of reused implementations sometimes need to use this.New
req.user.tenantto access the current user's tenant ID.Reflect
srv.events— base classcds.Serviceprovides a new gettersrv.eventsto reflect on declared events in the service definition, similar to the already existingsrv.entities,srv.types, andsrv.operations.Experimental
cds.ql(req)— event handlers can now use the like ofconst {SELECT} = cds.ql(req)to ensure transaction-managed and tenant-isolated execution of queries, instead ofsrv.tx(req). Note though, that this is an experimental feature, which might change or be removed in future versions.Switch on debug logs by setting the environmental variable
DEBUGtoyif you want to show more detailed log output.
More to Come Soon
As stated above, this major version update was just the start, setting the stage for new features with a greatly cleaned up implementations of our Node.js runtime's core.
In the documentation, you already find outlines, of not-yet documented or rarely filled-in guides and APIs, such as:
We didn't document and release these APIs right now, as we want to give them some more polishing before general availability.
Stay tuned for more to come in there.
Java Runtime
Important Changes for Former Java Stack ❗️
A minimum version 1.40.6 of the former CAP Java runtime is required.
Check your project's pom.xml and bump projects-parent-odatav2 or projects-parent to the latest version. We recommend doing this regularly.
Also, to benefit from new features, see our migration guide for the new CAP Java SDK.
Important Changes ❗️
- The API
CdsRuntime.runInRequestContext()has been deprecated and replaced byCdsRuntime.requestContext().run(). - The API
CdsRuntime.runInChangeSetContext()has been deprecated and replaced byCdsRuntime.changeSetContext().run(). - Some error codes were incorrect and have been corrected: The codes ranging from
40008to40017have been changed to400008to400017respectively, to prevent conflicts in error codes in the future. - The method
ServiceException.getLocalizedMessage()can't be used anymore for non-OData requests. Hence, if no activeRequestContextobject exists, use the new methodServiceException.getLocalizedMessage(Locale)to explicitly set a locale. The requests locale can be obtained from the CdsRuntime usingruntime.getProvidedParameterInfo().getLocale(). - XSUAA user names aren't normalized to lower case by default anymore (property
cds.security.xsuaa.normalizeUserNames) because XSUAA delivers stable case-sensitive user names as of now.
Modeling
- Support managed associations that don't target
keyelements- Support using
$nowinonconditions of unmanaged associations
- Support using
Code Generation
EventContextinterfaces for eventscreatemethod for consumption interfaces for structured types
CDS Data Store
- Managed Data
- handle
@cds.on.insert|updateannotations on data store level to set the values of current user ($user.id), session timestamp ($now) or a literal value - support managed data also upon deep insert or deep update
- handle
- support using the session context variable
$now,$at.from,$at.to,$user.id, and$user.localein filters
New RequestContext API
A new RequestContext API enables accessing and modifying request metadata like user information, query parameters, and HTTP headers.
In addition, a new Provider API enables applications to control how user or request parameter information is derived from the request.
Parametrized Views
Read requests on Parameterized views are now supported in OData V4. See section CDS > Definition Language > Exposed Entities for more details.
OData Features
The following new OData V4 features have been added:
- Updates on OData singletons and navigations from singletons to other entities are now supported.
- The expression
notis now supported in$filterrequests - The
$metadataendpoint now supports proper browser caching by setting the http headerCache-Control: max-age=0.- Data Aggregation (
$apply) - support for one level of data aggregation
- using transformations
groupby,aggregate,filter,searchandidentity - using the standard aggregation methods
sum,min,max,averageandcountdistinct - ordering by aggregated values
- using
$count=truetogether with
- Data Aggregation (
Fiori Drafts
You can now use field from draft enabled entities in orderBy clauses.
Miscellaneous
- Event handler methods can now use the types
CdsData,List<CdsData>, orStream<CdsData>for method arguments. - Support multiple bound XSUAA service instances --- The application configuration property
cds.security.xsuaa.serviceNamenow controls which XSUAA service binding is chosen for authorization.
Bug Fixes
- For an OData query with
$countoption, the inline count must be specified in the result. In the previous version, if no inline count was contained in the result, the row count was used, which could have resulted in wrong data. - Fixed a bug that caused queries using
COUNT(*), for example, OData's/$countto fail on SAP HANA databases. - Fixed a bug that caused PUT requests and actions to fail on Etag-enabled entities on SAP HANA.
- Fields annotated with
@cds.on.insertare now preserved in the draft when editing a draft enabled entity.
Performance
- Improved performance when querying a draft enabled entity.
- Suppress additional query for inline count if possible
- Reduce number of queries when expanding to-one associations
Multitenancy
Building Multitenant SaaS Applications with CAP
Create cost-efficient SaaS applications with CAP and SAP HANA Cloud by leveraging the multitenancy concepts of SAP Cloud Platform and the new Service Management instance management capabilities.
The cds-mtx library offers you out-of-the-box support to switch your single tenant scenario to multitenant persistency with tenant data separation using HDI containers and to integrate it with the SAP Cloud Platform SaaS Manager. See [Multitenancy] for more details.