Skip to Content
Technical Articles
Author's profile photo Archisman Das

End to End UI5 application on SAP BTP

The blog will take you through all the steps required to deploy a client and server side application on SAP BTP.


  • Basic knowledge of UI5
  • Basic node-express knowledge


Login/Register on the SAP BTP platform

SAP Business Technology Platform (formerly Cloud Foundry) is a PaaS offered by SAP to host your on-premise applications on cloud. To get started, login or register to the same using the below url:

Once you login for the first time, you should be able to see the below prompt appear.

Select “Continue to Trial Home”.

Next, you should see the following pop-up appear.

I will select Singapore as that’s the server closest to my current location and click on “Create Account”. The account creation takes a while, you should be able to see the below screen eventually.

Once you click “Continue”, you should be able to see the BTP Home Screen.

Click on “Go To Your Trial Account”. You will be redirected to a new url. Bookmark this for future use.


A “trial” sub-account was already created while creating our account. We will create our own.

Click on “Create”–>Subaccount. In the pop up that appears, give your sub-account some meaningful name and select the “US East AWS region”. Hit “Create”.

Create Cloud Foundry Environment

SAP BTP offers 2 environments to host/manage application viz. Cloud Foundry and Kyma. We will be using Cloud Foundry here. Go inside the newly created sub-account and click on “Enable Cloud Foundry”. Nothing needs to be changed in the pop up that follows. Hit “Create”.

Once enabled, we will need to create a “space” to deploy our application.

Click on “Create Space” and give it some meaningful name. Now your BTP platform is ready to have applications deployed onto it.



Install Cloud Foundry CLI

Download the package for your respective OS from below URL and install the same on your local machine. We will be using cloud foundry cli to push our applications to btp.

Once installed, open cmd and run cf –help. If installed properly, you should be able to see a list of available commands.


The Application

Our application will consist of 3 layers:

  • Database: PostgreSql
  • Business Logic: Node Js
  • UI: UI5

Provisioning the database

Inside your subaccount, click on Service Marketplace and search for “PostgreSql”.


Come back to cmd and login to your cloud foundry account using “cf login -a”. Provide your username and password which was used to create the btp account.

Create an instance of postgresql using the following command: “cf create-service postgresql-db trial my-post-db-02”. Here “postgresql-db” is the name of the service, “trial” is the service plan and “my-post-db-02” is the instance name. The instance creation takes about 10 mins. Once completed, run the command “cf services” and you should be able to see the service listed for your account.


Create a service key for the above instance from the portal. Give it a meaningful name and hit “Create” without modifying any other parameters. ** This is needed only if you are looking to test the connection to the above db instance from a standalone application residing outside of this cloud environment and not bound to this instance.

Creating the Node backend application

Now that our database instance is provisioned, we need to create our backend node application and bind the same to our database service.

Before initializing our node project, we will need to update our postgre service with a tag name which will be used by our node application to identify and bind to the service.

Open cmd and run the following command: cf update-service my-post-db-02 -t “my-post-db-02”

Create a new Node application using the “npm init -y” command. The main challenge here is to establish binding with the postgre service. We will be using the @sap/xsenv node module to achieve this.

Below is the dbConn.js file.

const promise = require('bluebird')
const xsenv = require('@sap/xsenv')
//const env = require('../default-env.json')

const optionsDbPromise = {
    promiseLib: promise
const pgp = require('pg-promise')(optionsDbPromise)

var conn_service = {}

try {
    //let envCredentials = env.VCAP_SERVICES['my-postgre-db'][0].credentials

    //xsenv.loadEnv() Only required for local testing and requires default-env.json file to be configured in root
    const envCredentials = xsenv.getServices({
        "my-post-db-02": { "tag": "my-post-db-02" }
    })["my-post-db-02"] = envCredentials.hostname
    conn_service.port = envCredentials.port
    conn_service.database = envCredentials.dbname
    conn_service.user = envCredentials.username
    conn_service.password = envCredentials.password
    conn_service.ssl = {
        rejectUnauthorized: false,
        ca: envCredentials.sslrootcert

} catch (error) {


const db = pgp(conn_service)

    .then((data) => {
        console.log('DB connection success ', data)
    }).catch((error) => {

module.exports = {

Above we are fetching our “my-post-db-02” service details using the tag filter which we updated earlier. Once these details are fetched, a db connection is created using the hostname, port, ssl root certificate, db name, username and password details for the service. The db instance is exported to be used in other files.

Next we need to write the apis which will directly interact with the db. Here we will only showcase creating a table, inserting data, fetching data and updating a record.

Below is our apis.js file.

const { db } = require("./dbConn")

const setupDB = (req, res, db, pgp) => {
    const QueryFile = pgp.QueryFile

    db.any(new QueryFile('./lib/sqlSetup.sql'), [])
        .then(data => {
            res.status(200).send({ "message": "DB setup successful" })
        }).catch(error => {
            res.status(500).send({ "message": error })

const getAllData = (req, res, db) => {
    return db.any("select * from ORGANIZATION_MGT.USER_LIST")
        .then(data => {
            res.status(200).send({ "message": data })
        }).catch(error => {
            res.status(500).send({ "message": error })

const updateUserData = (req, res, db) => {
    const id =
    const location = req.query.location
    return db.any(`update ORGANIZATION_MGT.USER_LIST set baselocation='${location}' where id='${id}'`)
        .then(data => {
            res.status(200).send({ "message": `User ${id} base location updated successfully!` })
        }).catch(error => {
            res.status(500).send({ "message": error })

module.exports = {

In the above file we have used a sqlSetup.sql file which is used to setup the table schema and insert data first time. Below is the script for the same.


INSERT INTO ORGANIZATION_MGT.USER_LIST VALUES ( '835825', 'Archisman', 'SCON', 'Pune' ), ( '835826', 'Anuj', 'LCON', 'Nagpur' ), ( '835827', 'Vaishali', 'LCON', 'Pune' ), ( '835828', 'Ritwika', 'LCON', 'Pune' );

Now we will setup the routes in our index.js file which is the entry point of our application. Below is the code for the same.

const express = require('express')
const cors = require('cors')
const { setupDB, getAllData, updateUserData } = require('./lib/apis')
const { db, pgp } = require('./lib/dbConn')

const app = express()
app.use(cors(), (req, res, next) => {
const port = process.env.PORT || 3000'/setup', (req, res) => {
    setupDB(req, res, db, pgp)

app.get('/users', (req, res) => {
    getAllData(req, res, db)
})'/users/:id', (req, res) => {
    updateUserData(req, res, db)

app.listen(process.env.PORT || 3000, () => {
    console.log(`App is running on port ${port}`)

Next, we will need to create the manifest.yaml file which consists of some essential information required by cloud foundry while creating the application in btp. Below is the code for the same.

- name: demo-node-app-01
  memory: 512M
  path: ./
  buildpack: nodejs_buildpack
  health-check-type: port
    - my-post-db-02

Upon creation of all the above files, this is how my project structure looks.


Deploying the Node application to BTP

Now that we have created our node application locally, it is time to push it to the cloud. Open cmd and navigate to the location where the manifest.yaml file (for the same node app) is location.

Run “cf push”. This will push the application to BTP and you should be able to see a route generated as shown below.

As a further check run the command “cf logs <app-name> –recent”. You should be able to see that the connection to the postgre service was successfully established.


Testing our apis using POSTMAN

Now that our backend is established, we should test our apis using postman before integrating with the client side application.

We have 3 rest end points to test.

  • POST /setup
  • GET /users
  • POST /users/:id?location

Below are snapshots for the same in postman.



Integrate api with client side application

Once we are satisfied that the apis are working properly, we can go ahead and integrate them to our client side application. I have provided the controller and view code snippet below showcasing the same.

], function (Controller, JSONModel, MessageBox) {
	"use strict";

	var oController
	return Controller.extend("Sample.Quickstart.controller.View1", {
		onInit: async function () {
			oController = this
			const oUserModel = new JSONModel()
			oController.getView().setModel(oUserModel, 'oUserModel')
			const sUrl = ``
			await oUserModel.loadData(sUrl, {}, true, 'GET')
		_onUpdateLocation: async (oEvent) => {

			const sPath = oEvent.getSource().getBindingContext('oUserModel').sPath
			const oUserModel = oController.getView().getModel('oUserModel')

			const id = oUserModel.getProperty(`${sPath}/id`)
			const location = oUserModel.getProperty(`${sPath}/baselocation`)

			try {
				const oUserUpdateModel = new JSONModel()
				const sUrl = `${id}?location=${location}`
				const oParams = {

				await oUserUpdateModel.loadData(sUrl, oParams, true, 'POST')


			} catch (error) {
<mvc:View controllerName="Sample.Quickstart.controller.View1"
	xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
	<App id="app">
			<Page id="page" title="Org Data" titleAlignment="Center">
					<Table items="{oUserModel>/message}">
								<Label text="User Id" design="Bold"/>
								<Label text="Name" design="Bold"/>
								<Label text="Designation" design="Bold"/>
								<Label text="Location" design="Bold"/>
								<Text text="{oUserModel>id}"/>
								<Text text="{oUserModel>username}"/>
								<Text text="{oUserModel>designation}"/>
									<Input width="80%" value="{oUserModel>baselocation}"/>
									<Button type="Emphasized" text="Udpdate" press="_onUpdateLocation"/>


Before pushing this application to the cloud, we once again need to create a manifest.yaml file to help cloud foundry with the deployment. Below is the code for the same.

- name: demo-ui5-app-01
  memory: 512M
  path: ./
  buildpack: staticfile_buildpack

The project structure now looks as below.


Pushing the client side application to cloud

In the same manner that we deployed our node application, open cmd and navigate to the location where the manifest.yaml file is situated.

Run “cf push”. Again a route will be generated for the application as shown below.


Now run the route in your browser and you should be able to see your application up and running. (Please note the /webapp/index.html that has been appended to the above route in the screenshot below)



And THAT’S IT!! You have successfully created an end to end application on cloud. I know this has been a long one, thanks for sticking through.

If you have any questions regarding any of the steps, feel free to reach out!

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Sadullah TANRIKULU
      Sadullah TANRIKULU

      Thanks a lot, nice blog, I hit the like and follow buttons. I expect more blogs, tutorials about how to debug a BTP app, how to build XML views, what is a yaml file and why use it in UI5 apps etc. from experts like you. Because these are very simple for you, but not for juniors like me. Thanks again. 👏

      Author's profile photo Deep Desai
      Deep Desai

      There is no PostgreSql available in the Service Marketplace for trial account. How did you use the same?

      Author's profile photo Archisman Das
      Archisman Das
      Blog Post Author

      If you are not able to see any service by default, you can add it from the Entitlements section inside your sub account.

      Author's profile photo Karthick Murugesan
      Karthick Murugesan

      Thanks for the detailed blog. It helps a lot. May I know the IDE that you used for Node and UI5 application development? Can we develop similar applications from Business Application Studio?

      Author's profile photo Archisman Das
      Archisman Das
      Blog Post Author

      I used vs code to develop the application locally before pushing it to the cloud. Yes, you may use BAS to develop such applications.

      Author's profile photo Harshitha B
      Harshitha B

      First of all thanks for the great blog.

      I tried to follow the instruction and did the steps. but i am getting following error

      And my manifest.yaml file looks like this:

      - name: example
        memory: 512M
        # path: ./
        buildpack: nodejs_buildpack
        health-check-type: port
        stack: cflinuxfs4
          - post
      It would be great if you could share the github repository link for the above project for reference.
      Author's profile photo Archisman Das
      Archisman Das
      Blog Post Author

      Hi Harshitha,


      Please run cf logs --recent to check whats causing the push to fail exactly.

      Author's profile photo Rohit Gera
      Rohit Gera

      Very Good Blog to start with BTP

      Author's profile photo Archisman Das
      Archisman Das
      Blog Post Author

      Thanks Rohit!