Skip to Content
Technical Articles
Author's profile photo Volker Buzek

cf for your pocket

or more precisely: running your UI locally Cloud Foundry-style, connected to a “real” Backend.

During my talk about the concept of a digital marketplace for the dive industry on this year’s UI5con, I showed a setup that mimics the SAP Cloud Platform Cloud Foundry (SAP CP cf) for local development.

Context

When developing an application following the guidelines of the Cloud Application Programming Model (CAP), a so-called mta file needs to be generated for deployment – either within the WebIDE or with the help of the CLI tool. The mta file can then be deployed to SAP CP cf.

The engine behind running the application on Cloud Foundry is the @sap/approuter.

It’s an npm module that delivers the UI as a webserver (“static resources” in the above diagram) and proxies service-requests to either local or remote URLs via the Cloud Platform’s “destination” concept.

And it’s possible to re-use all of that for local development!

local setup

It’s essentially a 3-step process (see my corresponding github repo for complete example)

  1. install @sap/approuter locally
    # make sure you have the sap npm repo set up:
    # npm config set @sap:registry https://npm.sap.com
    npm install @sap/approuter
  2. utilize @sap/approuter‘s runtime
    // index.js
    // note that xs-app.json in your "regular" SAP HANA XS
    // config file that's also required for any SAP CP cf-style
    // CAP-like application
    const approuter = require('@sap/approuter');
    const fs = require('fs');
    
    const xsAppConfig = JSON.parse(fs.readFileSync('xs-app.json', 'utf8'));
    const ar = approuter();
    ar.start({
        xsappConfig: xsAppConfig
    });
  3. configure destinations at runtime
    // xs-app.json
    {
      "authenticationMethod": "none",
      "welcomeFile": "/index.html",
      "routes": [
        {
          "source": "^/backend/(.*)$",
          "destination": "backend",
          "target": "$1"
        },
        {
          "source": "^/(.*)",
          "localDir": "./webapp",
          "cacheControl": "no-cache, no-store, must-revalidate"
        }
      ]
    }
    // index.js
    process.env.destinations = '[' +
        '{"name": "backend","url": "https://services.odata.org/V4/(S(fdng4tbvlxgzpdtpfap2rqss))/TripPinServiceRW/"}' +
        ']';

    The approuter interprets the node environment variable destinations – pass in an array of key-value pairs (name, url) and it will automagically proxy those requests for you! In the example above, every request to /backend ist automatically proxied to the TripIt OData Service at https://services.odata.org/...

    Important: the destination name of the route in xs-app.json and the name value in process.env.destinations must match!

Now, all that’s left is to fire up the engine:

node index.js

will present you http://localhost:5000 – including proxy access to the example OData Service via http://localhost:5000/backend

??

Assigned Tags

      3 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Marius Obert
      Marius Obert

      Hi Volker,

      a great blog post! This is a really handy trick?‍♂️ I will remember.

      Btw: It would be possible to get rid of the index.js file and to inject the environment variable via the start script:

      "scripts": {
          "start": "destinations='[{\"name\": \"backend\",\"url\": \"https://services.odata.org/V4/(S(fdng4tbvlxgzpdtpfap2rqss))/TripPinServiceRW/\"}]'  node node_modules/@sap/approuter/approuter.js"
      },

      I know this looks a little bit ugly because of the escaped quotation marks (and it’ll get more ugly, the more destinations you use).

      A further improvement could be achieved by the usage of dotenv which automatically imports data into the env var.

      "scripts": {
        "start": "node -r dotenv/config node_modules/@sap/approuter/approuter.js"
      },

      Whereby the destination is stored in the ‘.env’ file

      destinations='[{"name": "backend","url": "https://services.odata.org/V4/(S(fdng4tbvlxgzpdtpfap2rqss))/TripPinServiceRW/"}]'
      

       

       

      Author's profile photo Volker Buzek
      Volker Buzek
      Blog Post Author

      Hi Marius,

      nice abstraction case 🙂

      Best,

      Volker

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Volker,

      maybe you should update your blog with the information from:

      https://cap.cloud.sap/docs/node.js/authentication#jwt

      and:

      https://github.com/gregorwolf/SAP-NPM-API-collection/tree/master/apis/approuter#configurations

      to use the default-env.json to store the destination & XSUAA information.

      Best regards
      Gregor