The cds Façade Object
The cds
facade object provides access to all CAP Node.js APIs. Use it like that:
const cds = require('@sap/cds')
let csn = cds.compile(`entity Foo {}`)
Use cds repl
to try out things
For example, like this to get the compiled CSN for an entity Foo
:
[dev] cds repl
Welcome to cds repl v 7.3.0
> cds.compile(`entity Foo { key ID : UUID }`)
{ definitions: {
Foo: { kind: 'entity', elements: { ID: { key: true, type: 'cds.UUID' } } }
}}
Refs to Submodules
Many properties of cds are references to submodules, which are lazy-loaded on first access to minimize bootstrapping time and memory consumption. The submodules are documented in separate documents.
- cds. model
- cds. server
- cds. serve()
- cds. services
- cds. middlewares
- cds. protocols
- cds. auth
- cds. connect
- cds. ql
- cds. tx()
- cds. log()
- cds. env
- cds. auth
- cds. i18n
- cds. test
- cds. utils
Import classes and functions through the facade object only:
Good:
const { Request } = require('@sap/cds')
Bad:
Never code against paths inside @sap/cds/
:
const Request = require('@sap/cds/lib/.../Request')
Builtin Types & Classes
Following properties provide access to the classes and prototypes of linked CSNs.
cds. builtin .types
cds. linked .classes
The following top-level properties are convenience shortcuts to their counterparts in cds.linked.classes
.
For example:
cds.entity === cds.linked.classes.entity
Core Classes
cds. Service
cds. EventContext
cds. Event
cds. Request
cds. User
Properties
Following are properties which are not references to submodules.
cds. version
Returns the version of the @sap/cds
package from which the current instance of the cds
facade module was loaded. For example, use that to write version specific code:
const [major, minor] = cds.version.split('.').map(Number)
if (major < 6) // code for pre cds6 usage
cds. home
Returns the pathname of the @sap/cds
installation folder from which the current instance of the cds
facade module was loaded.
[dev] cds repl
> cds.home
~/.npm/lib/node_modules/@sap/cds
cds. root
Returns the project root that is used by all CAP runtime file access as the root directory. By default this is process.cwd()
, but can be set to a different root folder. It's guaranteed to be an absolute folder name.
// Print current project's package name
let package_json = path.join (cds.root,'package.json')
let { name, description } = require(package_json)
console.log ({ name, description })
cds. cli
Provides access to the parsed effective cds
cli command and arguments. Example: If you would add log respective output in a project-local server.js
, and start your server with cds watch
, you'd see an output like this:
Trace : {
command: 'serve',
argv: [ 'all' ],
options: {
'with-mocks': true,
'in-memory?': true
}
}
For example, cds-plugins
can use that to plug into different parts of the framework for different commands being executed.
Known values for cds.cli.command
are add
, build
, compile
, deploy
, import
, init
, serve
. cds watch
is normalized to serve
.
cds. entities
Is a shortcut to cds.db.entities
. Used as a function, you can specify a namespace.
cds. env
Provides access to the effective configuration of the current process, transparently from various sources, including the local package.json or .cdsrc.json, service bindings and process environments.
[dev] cds repl
> cds.env.requires.auth
{
kind: 'basic-auth',
strategy: 'mock',
users: {
alice: { tenant: 't1', roles: [ 'admin' ] },
bob: { tenant: 't1', roles: [ 'cds.ExtensionDeveloper' ] },
# ...,
'*': true
},
tenants: {
t1: { features: [ 'isbn' ] },
t2: { features: '*' }
}
}
cds. requires
... is an overlay and convenience shortcut to cds.env.requires
, with additional entries for services with names different from the service definition's name in cds models. For example, given this service definition:
service ReviewsService {}
... and this configuration:
{ "cds": {
"requires": {
"db": "sqlite",
"reviews" : { // lookup name
"service": "ReviewsService" // service definition's name
}
}
}}
You can access the entries as follows:
[dev] cds repl
> cds.env.requires.db //> the effective config for db
> cds.env.requires.reviews //> the effective config for reviews
> cds.env.requires.ReviewsService //> undefined
[dev] cds repl
> cds.requires.db //> the effective config for db
> cds.requires.reviews //> the effective config for reviews
> cds.requires.ReviewsService //> same as cds.requires.reviews
The additional entries are useful for code that needs to securely access the service by cds definition name.
Note: as cds.requires
is an overlay to cds.env.requires
, it inherits all properties from there via prototype chain. In effect using operations which only look at own properties, like Object.keys()
behave different than for cds.env.requires
:
[dev] cds repl
> Object.keys(cds.env.requires) //> [ 'db', 'reviews' ]
> Object.keys(cds.requires) //> [ 'ReviewsService' ]
cds. services
A dictionary and cache of all instances of cds.Service
constructed through cds.serve()
, or connected to by cds.connect()
.
It's an iterable object, so can be accessed in the following ways:
let { CatalogService, db } = cds.services
let all_services = [ ... cds.services ]
for (let k in cds.services) //... k is a services's name
for (let s of cds.services) //... s is an instance of cds.Service
cds. context
Provides access to common event context properties like tenant
, user
, locale
as well as the current root transaction for automatically managed transactions.
Learn more about that in reference docs for cds.tx
.
cds. model
The effective CDS model loaded during bootstrapping, which contains all service and entity definitions, including required services. Many framework operations use that as a default where models are required. It is loaded in built-in server.js
like so:
cds.model = await cds.load('*')
Learn more about bootstrapping in cds.server
.
cds. app
The express.js Application object constructed during bootstrapping. Several framework operations use that to add express handlers or middlewares. It is initialised in built-in server.js
like so:
cds.app = require('express')()
Learn more about bootstrapping in cds.server
.
cds. db
A shortcut to cds.services.db
, the primary database connected to during bootstrapping. Many framework operations use that to address and interact with the primary database. In particular that applies to the global cds.ql
statement objects. For example:
let books = await SELECT.from(Books) // is a shortcut for:
let books = await cds.db.run ( SELECT.from(Books) )
It is initialized in built-in server.js
like so:
cds.db = await cds.connect.to('db')
Learn more about bootstrapping in cds.server
.
Methods
cds. error()
function cds.error (
message : string | object,
details? : object
caller? : function
)
This is a helper to construct new errors in various ways:
let e = new cds.error ('message')
let e = new cds.error ('message', { code, ... })
let e = new cds.error ({ message, code, ... })
If called without new
the error is thrown immediately allowing code like that:
let e = foo || cds.error (`Expected 'foo' to be truthy, but got: ${foo}`)
You can also use cds.error
with tagged template strings:
let e = foo || cds.error `Expected 'foo' to be truthy, but got: ${foo}`
In contrast to basic template strings, passed in objects are added using Node's
util.format()
instead oftoString()
.
Method cds.error.expected
allows to conveniently construct error messages as above:
let e = foo || cds.error.expected `${{foo}} to be truthy`
Optional argument caller
can be a calling function to truncate the error stack. Default is cds.error
itself, so it will never show up in the stacks.
cds. exit()
Provides a graceful shutdown for running servers, by first emitting cds.emit('shutdown')
with handlers allowed to be async
functions. If not running in a server, it calls process.exit()
cds.on('shutdown', async()=> fs.promises.rm('some-file.json'))
cds.on('shutdown', ()=> console.log('shutdown'))
cds.exit() //> will rune above handlers before stopping the server
Lifecycle Events
The cds
facade object is an EventEmitter, which frameworks emits events to, during the server bootstrapping process, or when we compile models. You can register event handlers using cds.on()
like so:
const cds = require('@sap/cds')
cds.on('bootstrap', ...)
cds.on('served', ...)
cds.on('listening', ...)
- Learn more about Lifecycle Events emitted by
cds.compile
- Learn more about Lifecycle Events emitted by
cds.server
WARNING
As we're using Node's standard EventEmitter, event handlers execute synchronously in the order they are registered, with served
and shutdown
events as the only exeptions.