Search

Grow As You Go…

This section contains best practices for speeding up development by jump-starting projects with zero setup, eliminating boilerplate code, and parallelizing work.

Jump-Starting Projects

Assuming that you’ve installed @sap/cds-dk, jump-starting a project in CAP is as simple as this:

mkdir demo && cd demo  # create a new project folder
cds watch              # ask cds to watch for things to come
Convention over Configuration

Following the principles of Convention over Configuration, CAP provides defaults for many things that you’d have to configure in other frameworks. Stay within the confines of these defaults to benefit from things just working automatically. You can always override the defaults by adding your own configurations.

Zero Setup

The project folder is empty at the beginning, so there’s really no setup required. No config files, no manifests whatsoever. The simple reason is that we don’t need them in these early phases of a project. We may need some later on, for example, when we reach the step about Deploying to the Cloud, but there’s no need to bother with this now.

Contracts First

Most frequently, CAP projects are about creating services. Service definitions describe the API contract between a service provider and its consumers. To speed things up, you can quickly create an all-in-one service as follows:

copy and paste this into a file srv/cat-service.cds:

@path:'/browse'
service CatalogService {

  entity Books {
    key ID : UUID;
    title  : String;
    descr  : String;
    author : Association to Authors;
  }

  entity Authors {
    key ID : UUID;
    name   : String;
    books  : Association to many Books on books.author=$self;
    birth  : Date;
    death  : Date;
  }

}
Prefer Top-Down Approaches

Instead of following a bottom-up approach, starting from the data model, then putting services on top, then adding UIs, and so on, it’s much better to apply a top-down approach as follows:

  1. Roughly sketch your application’s usage and use-cases, for example, your UIs.
  2. Capture required interfaces in use case-oriented service definitions.
  3. Start building the actual UIs on top, and in parallel…
  4. Have other teams working on the data models below.

This (a) allows you to separate and parallelize work loads and (b) results in much better service interfaces than the one you’d get by using the bottom-up approach.

Running Out-of-the-Box

When we save the file we created in the former step, the cds watcher in the terminal immediately reacts, showing this output:

[cds] - connect to datasource - sqlite::memory:
[cds] - serving CatalogService at /browse
[cds] - service definitions loaded from:

  srv/cat-service.cds
  node_modules/@sap/cds/common.cds

[cds] - server listening on http://localhost:4004 ... (terminate with ^C)
[cds] - launched in: 355.732ms
Full-Fledged OData Services

Click the link http://localhost:4004, … et voila, we are in contact with a full-fledged OData service (for example, see $metadata​) in which we can even start Fiori previews to get idea of what a UI might look like.

Let’s do some ad hoc tests:

Served by Generic Providers

What we see here are the effects of Generic Providers, which handle many things out of the box, such as compiling the CDS models into OData $metadata documents on the fly, as well automatically serving all CRUD requests, thereby handling all the OData protocol features such as $batch, up to complex choreographies such as Fiori Draft. This saves us lots of work at this point and allows us to immediately go on with the next steps instead of implementing all of this in boilerplate code.

Learn more about generic providers.

Mocking App Services

Use cds run --in-memory to quickly start a lightweight Node.js server with sqlite’s transient in-memory database instead of always deploying to and connecting to your target database. Do that not only in Node.js projects but also as a mock server in Java projects, for example, for frontend-related tasks, or as a mock up for remote services to integrate with.

Prerequisites

The sample mock server created in the following steps is based on the mock server developed in the TechEd 2019 tutorial Creating an SAP S/4HANA Extension with SAP Cloud Application Programming Model and SAP Cloud SDK.

Create a Project for the Mock Server
  1. Create an empty project for the mock server by executing cds init mockserver in the terminal.
  2. Execute code mockserver to open the newly created project in VSCode.
  3. Open the package.json file and add "@sap/cds-dk": "^1.0.0" as a dependency. Execute npm i to install all dependencies.
Add Service API Definition
  1. Download the service API definition from the SAP API Business Hub in EDMX format.
  2. Import the downloaded API definition by running cds import ~/Downloads/API_BUSINESS_PARTNER.edmx. This converts the EDMX service API definition to a Core Schema Notation (CSN) definition and places it into a local subfolder srv/external.
Add a Dummy services.cds File
  1. In the srv folder, create a file named services.cds.
  2. Add this line in the file:
using { API_BUSINESS_PARTNER } from './external/API_BUSINESS_PARTNER';

Keep this file empty to serve imported APIs the default way. It can be used to tailor the mock server to your specific needs, for example, by adding or overriding certain definitions.

Run the Mock Server
  1. Execute cds run --with-mocks --in-memory to start the mock server with in-memory database.

Alternatively you can execute cds watch, which essentially is a shortcut to the same cds run command but also starts a monitor to restart the server automatically if sources are changed.

Optionally Add Sample Data
  1. Create a new file init.js in the srv folder.
  2. Paste the following code:
module.exports = (db)=>{
  const { A_BusinessPartnerAddress: Addresses } = db.entities(
    'API_BUSINESS_PARTNER'
  )
  return cds.run ([
    INSERT.into(Addresses).columns(
      'BusinessPartner',
      'AddressID',
      'CityName',
      'StreetName'
    ).rows(
      [ '1003764', '28238', 'Walldorf', 'Dietmar-Hopp-Allee' ],
      [ '1003765', '28241', 'Palo Alto', 'Hillview Avenue' ],
      [ '1003766', '28244', 'Hallbergmoos', 'Zeppelinstraße' ],
      [ '1003767', '28247', 'Potsdam', 'Konrad-Zuse-Ring' ]
    )
    // add more INSERTs here, as appropriate
  ])
}
Mock Custom Responses

To extend the mock server with custom logic, you can create a custom handler. To do so, create a .js file with the same name next to the imported service definition file, in our case srv/external/API_BUSINESS_PARTNER.js. Add the custom logic there:

module.exports = cds.service.impl (srv => {
  // add your custom handlers here...
})
Mock Error Cases

To create error cases, explicitly return errors in a custom handler by using the req.error or req.reject functions. For example, add the following code in the API_BUSINESS_PARTNER.js file:

module.exports = cds.service.impl(srv => {
  srv.before('READ', 'A_BusinessPartnerAddress', req => {
    const { BusinessPartner, AddressID:ID } = req.data
    if (BusinessPartner === '1003764' && ID === '28238')
      req.reject (500, 'Your error message.')
  })
})

To trigger this error, use the following request:

http://localhost:4004/api-business-partner/A_BusinessPartnerAddress(BusinessPartner='1003764',AddressID='28238')
Reset Mock Data at Runtime

To reset the mock data at runtime without restarting the mock server, define an unbound action.

When using cds watch, executing rs in the terminal with the running watch command will restart the mock server and reset the mock data without the need of an unbound action.

Declare the action in the mock service definition. In srv/services.cds add the following code:

extend service API_BUSINESS_PARTNER with {
  action reset();
}

In srv/external/API_BUSINESS_PARTNER.js add the implementation of the action:

    srv.on('reset',async () => {
        const db = await cds.connect.to('db')
        await db.run(()=> require('../init')(db))
    })

This will delete the data from the database and fill it with the initial data.

Trigger the reset action with the following POST request:

http://localhost:4004/api-business-partner/reset

… for External Services

Growing On…

  • Integrating foreign Services
  • Serving UIs
  • Adding i18n
  • Adding Persistent Data
  • Adding Localized Data
  • Adding Temporal Data
  • Adding Authorization
  • Adding Audit Logging
  • Adding Audit Logging
  • Adding Data Privacy
  • Connecting to the Cloud
  • Deploying to the Cloud
  • Adding Tests
  • Adding CI/CD

Deploying to the Cloud

CAP applications can be deployed to the SAP Cloud Platform Cloud Foundry environment. In the end, it’s about deploying regular Node.js and/or Java applications, and about creating and binding appropriate service instances (see the CF Developer Guide). For more details, see Deploying to the Cloud.

Show/Hide Beta Features