Skip to content
On this page

Prototyping with SAP CAP

Deep dive workshop to learn more about:

FullScreen mode

There's built-in support for fullscreen mode. Press F on your keyboard to view the presentation in fullscreen mode. Once in fullscreen mode, press the ESC key to exit.

UDINA Trial Sub Account

In connection with the UNIORG SAP BTP workshop, UNIORG offers a time-limited trial sub-account that can be used for an initial introduction to development with SAP BTP.

The sub-account can be connected to the SAP Cloud Connector to securely access on-premise systems from the SAP BTP Cloud.

Plan Restrictions

  • Developer Access
    • 5 named S-User
      How to Generate a new S-User ID
    • Authorizations
      • SAP Business Application Studio Developer
      • Cloud Connectivity and Destination Admin
      • SAP BTP SubAccount Viewer
  • Cloud Foundry Quota Plan
    • Runtime Memory: 512 MByte
    • Routes: 4
    • Service Instances: 8
    • App Instances: 4
    • No paid service plans
  • Business Application Studio – Free Plan
    • A user can only have up to 2 dev spaces.
    • A user can only have 1 dev space in the RUNNING state at a time.
    • The maximum size limit of a dev space is 4 GB.

Setup your DEV Space

Launch My DEV Spaces

SAP BAS Dev Spaces

Create CAP DEV Space

Choose Full Stack Cloud Application application and press

Create CAP Dev Space

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.

Get started with SAP Business Application Studio

Jumpstarting Project

The following steps show creating new projects with a SAP BAS Template, but it is also possible by using the CDS Development Kit.

Start with template wizzard

Start from template

Choose CAP Project

Choose CAP Project

Enter CAP Project Details

CAP Project Details

Project Storyboard

Project Storyboard

Create External Data Model

Option 1 (BAS Admin) : Add destination with Service Center

Having the role BAS Admin, the data model can be created using the Storyboard.

Story Board – Create a data model

The Service Center opens up and then add a new SAP System for your udina-<customer>-trial subaccount.

BAS Service Center - Add Northwind Destination

Option 2 (Destination Admin) : Create destination with SAP BTP Cockpit

If you are assigned to the role BAS Admin, but you are allowed to create BTP Destinations, you can manually add a relevant service destination.

Open the BTP Cockpit section Connectivity -> Destinations and create a New Destination with the following settings:

Destination ConfigurationValue
DescriptionoData V2 Demo Service
Proxy TypeInternet
Additional PropertiesValue

Full Path is mandatory

BAS currently only supports service destinations with full path

Add External Data Model

Use Service Action Add External Data Model to CAP Project to add service to CAP project.

Add External Data Model to CAP Project
Add Northwind Data Model to CAP Project

Check, if BAS created the relevant package.json service section:

"cds": {
    "requires": {
        "Northwind": {
            "kind": "odata-v2",
            "model": "srv/external/Northwind",
            "[production]": {
                "credentials": {
                    "destination": "Northwind"

Use real destination for development by adding default-env.json


The usage of default-env.json is generally deprecated and cds bind should be used instead, but it needs a deployed service. To overcome this chicken-egg problem (testing before deployment), we will use this approach for demo purposes.

    "VCAP_SERVICES": {},
    "destinations": [
            "name": "Northwind",
            "url": ""

Remove production switch from package.json

Just delete the marked lines from existing code and use context menu Format Document to fix text indent:

"cds": {
    "requires": {
        "Northwind": {
            "kind": "odata-v2",
            "model": "srv/external/Northwind",
            "[production]": { 
                "credentials": {
                    "destination": "Northwind"

Restart CDS service in terminal to load destination environment

cds watch

Test external service


Add missing dependencies for external oData V2 support

Missing dependency error @sap-cloud-sdk/http-client

Since CAP is a glue framework and by default uses oData v4, you need to add missing dependency @sap-cloud-sdk/http-client to add oData v2 support for external service consumption.

npm i @sap-cloud-sdk/http-client

Re-Test external service


Mashing up with Remote Services

Combining local and remote services using Mashing.

Enhance cat-service.cds

using my.bookshop as my from '../db/data-model';
using Northwind from './external/Northwind.cds';

service CatalogService {
    @readonly entity Books as projection on my.Books;
    @readonly entity Customers as projection on Northwind.Customers;

Create new cat-service.js service implementation

const cds = require('@sap/cds');

module.exports = cds.service.impl(async function () {
    const Northwind = await'Northwind');

    this.on('READ', 'Customers', req => {
        //console.log("read external customers", req.query);

REST Client

The REST Client for Visual Studio Code allows you to send HTTP request and view the response in Visual Studio Code directly (similarly to Postman).

Create a ./test folder and add a file service.http with content.

GET http://localhost:4004/catalog/Books
GET http://localhost:4004/catalog/Customers

### Example POST service call with CSRF token
@host = https://my-sap-system:443
@path = /sap/opu/odata/sap/api_purchasereq_process_srv/

# @name fetchToken
HEAD {{host}}{{path}}
Authorization: Basic {{$dotenv USERNAME}} {{$dotenv PASSWORD}}
X-CSRF-Token: Fetch


# @name createPurchaseRequisition
POST {{host}}{{path}}A_PurchaseRequisitionHeader
Authorization: Basic {{$dotenv USERNAME}} {{$dotenv PASSWORD}}
X-CSRF-Token: {{fetchToken.response.headers.x-csrf-token}}
Content-Type: application/json     

    data: {}

Externalize sensitive data to ./test/.env and exclude it from git inside .gitignore


Enhance Bookshop Data Model

Enriching the book shop similarly to tutorial Build a Business Application Using CAP for Node.js, which focuses on local CAP development with VS Code.

Enhance ./db/data-model.cds

namespace my.bookshop;

using {
} from '@sap/cds/common';

entity Books {
  key ID     : Integer;
      title  : localized String;
      author : Association to Authors;
      stock  : Integer;

entity Authors {
  key ID    : Integer;
      name  : String;
      books : Association to many Books
                on = $self;

entity Orders : managed {
  key ID      : UUID;
      book    : Association to Books;
      country : Country;
      amount  : Integer;

Enhance ./srv/cat-service.cds

using my.bookshop as my from '../db/data-model';
using Northwind from './external/Northwind.cds';

service CatalogService {
    entity Books     as select from my.Books;
    entity Authors   as select from my.Authors;
    entity Orders    as select from my.Orders;

    entity Customers as projection on Northwind.Customers;

Add initial data ./db/data/my.bookshop-Authors.csv

Use CAP DATA MODELS AND SERVICES view to create sample,

101;Emily Brontë
107;Charlote Brontë
150;Edgar Allen Poe
170;Richard Carpenter

Replace initial data ./db/data/my.bookshop-Books.csv with

201;Wuthering Heights;101;12
207;Jane Eyre;107;11
251;The Raven;150;333

Test expand


Localize data

Copy ./db/data/my.bookshop-Books.csv to ./db/data/my.bookshop-Books_texts.csv

201;de;DE Wuthering Height
201;en;EN Wuthering Height

Test locales


Add Virtual Element

Virtual Elements allow to implement calculated chracteristics. This keyword indicates that this element isn’t added to persistent artifacts.

Add Books virtual element stockState inside data-model.cds

entity Books {
  key ID                 : Integer;
      title              : localized String;
      author             : Association to Authors;
      stock              : Integer;
      virtual stockState : String enum { 
        Error       = 'Error'; 
        Information = 'Information'; 
        None        = 'None'; 
        Success     = 'Success'; 
        Warning     = 'Warning'; 

Add custom logic ./srv/cat-service.js

this.after('READ', 'Books', each => {
    // Add some discount for overstocked books
    if (each.stock > 111) each.title += ' -- 11% discount!'

    // Calculate Virtual stock state to highlight critical stocks
    each.stockState = (each.stock < 20) ? 'Warning' : 'None'

Deploy to SAP BTP

Following the SAP CAP Cookbook Deploy to Cloud Foundry, the CAP command-line tool helps to prepare the project for the deployment to SAP BTP.

How SAP CAP project folders deploy to SAP BTP

uml diagram

Using XSUAA-Based Authentication

Configure your app for XSUAA-based authentication:

cds add xsuaa --for production

The following files have been generated:

manifest.ymlCloud Foundry App Manifest
mta.yamlMTA Development Descriptor
xs-security.jsonApplication Security Descriptor

Using MTA-Based Deployment

We’ll be using the Cloud MTA Build Tool to execute the deployment:

cds add mta

The mta.yaml has been updated by adding a module for the CAP service, that is referencing the XSUAA resource.

Restrict the memory usage of your CAP service (defaults to 1024M) by adding a memory parameter to the CAP module:

  - name: workshop-srv
    type: nodejs
    path: gen/srv
      buildpack: nodejs_buildpack
      memory: 256M

Using a local SQLite database

Instead of using a production-ready cloud database, our prototyping will use the sqlite3 in-memory database instead.

Move sqlite from devDependencies to dependencies (prod):

npm i sqlite3 -P

Edit mta.yaml to auto build the prototype database

    - builder: custom
        - npx -p @sap/cds-dk cds build --production
        - npx -p @sap/cds-dk cds deploy --to sqlite:gen/srv/srv/db.sqlite --no-save

Add database dependency to package.json

    "[production]": {
        "db": {
            "kind": "sqlite",
            "credentials": {
                "database": "srv/db.sqlite"

Using Custom App Router as Gateway

For scenarios without SAP Fiori Launchpad, the app router needs to be deployed along with your application:

cds add approuter --for production

The following files have been generated:

app/default-env.jsonLocal environment destination injections
app/package.jsonNode.js Approuter metadata
app/xs-app.jsonApplication Routing Configuration

The mta.yaml has been updated by adding the approuter module.

Add helper scripts to package.json

"scripts": {
    "start": "cds run",
    "watch": "cds watch",        
    "build": "rimraf resources mta_archives && mbt build --mtar archive",
    "deploy": "cf deploy mta_archives/archive.mtar --retries 1",
    "target:test": "cf target -o udina-<customer>-trial -s services"

Build Services

Make sure to install formerly added services to node_modules:

npm i

and trigger the build archive process using the build script.

The following file have been generated:

mta_archives/archive.mtarMTA Archive

Deploy Services

Login to Cloud Foundry using CTRL SHIFT P and select option:

CF: Login to Cloud Foundry

or alternatively use terminal command line cf login.

Make sure to use the right deployment target

Check that you are using the cf deployment target udina-<customer>-trial to avoid deploying into wrong SAP BTP Sub Account!

Test Services

Open the SAP BTP Cockpit for the Sub Account udina-<customer>-trial and open the Cloud Foundry Space services.

The deployment created two applications:

workshopThe application router
workshop-srvThe CAP service

Test the services.

Try to open Northwind Customers entity set, that is returning an error:


Error during request to remote service: Failed to load destination.

Create SAPUI5 freestyle Applicatiom

  • Use CTRL SHIFT P and select option Fiori: Open Application Generator to start the Template Wizard.
  • Choose Application Type: SAPUI5 freestyle
  • Select SAPUI5 Application
  • Choose Next
  • Select Data Source: Use a Local CAP Project
  • Choose your CAP project: workshop
  • Chosse OData service: CatalogService
  • Choose Next
  • Choose View name: View
  • Choose Next
  • Choose Module name: freestyleui5
  • Choose Application title: Freestyle UI5
  • Make sure, option Add deployment configuration to MTA project is checked
  • Choose Next
  • Choose Target: Cloud Foundry
  • Choose Destination name: None
  • Choose Next

Investigate changes

Investigate changes inside mta.yaml and see new entries:

  • modules
    • workshop-app-content
    • freestyleui5
  • resources
    • workshop-repo-host
    • workshop-destination-service

Implement UI5 view

Replace <content/> with marked lines inside View.view.xml

<mvc:View controllerName="freestyleui5.controller.View" displayBlock="true"
    xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc">
    <Page id="page" title="{i18n>title}">
        <List id="list" items="{/Books}">
            <StandardListItem title="{title}" info="{stock}"/>

Exclude app sources from Approuter

Change mta.yaml to skip app

- name: workshop
  type: approuter.nodejs
  path: app/
    ignore: ["freestyleui5/"]

Deploy Updates

  • Build MTA
  • Deploy MTA

Investigate HTML5 Application Repository

cf html5-info
cf html5-list

Bound HTML5 repository runtime to Approuter

Add missing dependencies inside mta.yaml

  - name: workshop-repo-runtime
    - name: workshop-repo-runtime
    type: org.cloudfoundry.managed-service    
        service: html5-apps-repo    
        service-plan: app-runtime

Bound Destination resource to CAP

Add missing dependencies inside mta.yaml

  - name: workshop-destination-service

Add missing HTML5 route to Approuter

Edit app/xs-app.json:

    "source": "^/freestyleui5(/.*)",
    "target": "/freestyleui5/$1",
    "service": "html5-apps-repo-rt",
    "authenticationType": "xsuaa"

Deploy Updates

  • Build MTA
  • Deploy MTA

Test services

  • Test Freestyle UI5 application
  • Test Northwind /catalog/Customers service using destination

Quick fix freestyleui5 app relative service path

Add route to app/freestyleui5/xs-app.json

    "source": "^/catalog/(.*)$",
    "destination": "srv-api",
    "authenticationType": "xsuaa",
    "csrfProtection": true

Deploy Updates

  • Build MTA
  • Deploy MTA

Create SAP Fiori elements UX

comming soon...

Undeploy your project

Use the generated script undeploy or manually call:

cf undeploy workshop --delete-services --delete-service-keys --delete-service-brokers

OData briefly explained

Powering SAP BTP There are various ways to learn about OData and starting with the native HTTP request may be the most direct one. Read Learning more or the Full Documentation for further details.

Entity Data Model (EDM)

OData ResourceSimilar toIs Described in an Entity Data Model by
CollectionTableEntity Set - A navigation property on an entity type that identifies a collection of entities
EntryStructureEntity Type - Note: Entity Types may be part of a type hierarchy
Property of an entryFieldPrimitive or Complex Entity Type Property
Complex TypeDeep StructureComplex Type
LinkRelationA Navigation Property defined on an Entity Type
Service OperationBAPIFunction Import

URI Convention

A URI used by an OData service has up to three significant parts:

  • the service root URI
  • resource path
  • query string options.
OData URI Convention

Example Calls

MethodTaskURI Segment
GETRequest resources/Books
GETRequest individual resource/Books(201)
GETInvoke function/Books(201)/ns.rateAuthor()
POSTCreate resource/Books { ID: 999, title: "abc", stock: 3 }

Query String Options

$selectSubset of properties to be returned
$orderbySpecifies an expression for determining what values are used to order the collection of Entries
$topIdentifies a subset of the Entries in the Collection of Entries
$skipSkips N entries in the result of the Collection of Entries
$filterFilters a subset of the Entries in the Collection of Entries
Operators: Eq,Ne,Gt,Ge,Lt,Le,And,Or,Not
Functions: substringof,endswith,startswith,lnegth,indexof,tolower,toupper,trim,concat
$expandReturns linked navigation properties inlined with the results
$formatReturned data format [Atom,Xml,Json,Xlsx(ABAP)...IANA-defined-content-type]
$count=trueResult includes a count of the number of Entries in the Collection