Skip to Content
Technical Articles
Author's profile photo Ioana Stefania Santimbrean

Part 1: How to build an extension application for SAP S/4HANA Cloud using CAP, SAP Cloud SDK and SAP Fiori elements

SAP S/4HANA Cloud customers have their own specific business needs. Some of these business needs can be implemented using In-App Extensibility, but some of them require Side-by-Side Extensibility. This blog post series covers how to do Side-by-Side Extensibility by building an application on SAP Cloud Platform.

More specific, how to build the application using SAP Cloud Application Programming Model – Node.js, SAP Cloud SDK – JavaScript and SAP Fiori elements.

What to expect from this blog post series?

The purpose of this blog post series is to showcase the end-to-end technical knowledge of building an extension application using the mentioned technologies. The application will follow a simple business scenario and will focus on implementation steps.

I will cover a step-by-step tutorial with code snippets, screenshots and explanations of how to develop and configure the application.

What’s the business scenario?

In the SAP S/4HANA Cloud system we have Business Partner Master Data. Let’s imagine we want some end-users to be able to modify the Addresses of these Business Partners.

Part 1: Building a CAP application

This part will cover how to use SAP Cloud Application Model following these main steps:

  • Generate a new extension application using CAP
  • Call SAP API Business Hub sandbox
  • Configure, build and deploy the application on SAP Cloud Platform
  • Add OData V2 adapter and READ one entity

What are the prerequisites for this part?

You should follow the blog post Part 0 from this series or have the following:

  • URL for the OData service
  • User and password for Basic Authentication

Access to:

  • SAP S/4HANA Cloud system
  • SAP Cloud Platform (you can create a trial account) with Cloud Foundry subaccount

Install:

  • Node.js (use the latest LTS version)
  • @sap/cds-dk globally by running in a Terminal the command: npm i -g @sap/cds-dk
  • SQLite if in you are using Windows: https://sqlite.org/download.html
  • cf CLI: https://docs.cloudfoundry.org/cf-cli/install-go-cli.html
  • MTA Build Tool: npm install -g mbt
  • CLI plugin for Multi-Target Application (MTA) operations in Cloud Foundry by running the command: cf install-plugin multiapps
  • Visual Studio Code
  • VS Code extension SAP Fiori tools – Extension Pack

If you want to avoid installing the prerequisites use SAP Business Application Studio instead of Visual Studio Code. Create a dev space for SAP Cloud Business Application. SAP Business Application Studio is also available in the SAP Cloud Platform trial account.

SAP S/4HANA Cloud system access is needed, but the initial steps can be done using the SAP API Business Hub sandbox. So don’t give up yet if you don’t have access!

Generate a new extension application using CAP

Steps to follow:

  1. Open a Terminal in a directory where you want the project to be stored and run the following command: cds init cap-adman
  2. Go to SAP API Business Hub and in the right upper corner press on Log on.
  3. Look for SAP S/4HANA Cloud Business Partner (A2X) OData API. Click on Details and then on Download API Specification and choose EDMX.
  4. Copy and paste the .edmx file in the project folder /cap-adman.
  5. In Visual Studio Code, open a Terminal which is pointing to the /cap-adman folder and run the command: cds import API_BUSINESS_PARTNER.edmx. In your project in the /srv folder, you will see now an /external folder where you can find the .edmx downloaded file and the .csn file generated by cds.
  6. Under /srv folder create a file address-manager-service.cds and copy the following contents inside it:
    using {API_BUSINESS_PARTNER as external} from './external/API_BUSINESS_PARTNER.csn';
    
    service AddressManagerService {
    
        @readonly
        entity BusinessPartners         as projection on external.A_BusinessPartner {
            BusinessPartner, LastName, FirstName, to_BusinessPartnerAddress
        };
    
        entity BusinessPartnerAddresses as projection on external.A_BusinessPartnerAddress {
            BusinessPartner, AddressID, Country, PostalCode, CityName, StreetName, HouseNumber
        }
    
    };
  7. For initial testing purposes we will create some mock data and run the app. Under /external folder create folder /data and inside of it a file with this exact name: API_BUSINESS_PARTNER-A_BusinessPartner.csv and paste the following contents inside of it:
    BusinessPartner;LastName;FirstName
    30413010;Smith;John
    30413011;Thomson;Georg​
  8. Open a Terminal and run the following command: cds watch
  9. Go to http:localhost:4004/ and navigate to http://localhost:4004/address-manager/BusinessPartners to see the mock data.

Call SAP API Business Hub sandbox

Steps to follow:

  1. Open a Terminal and run: npm install
  2. Open the package.json file and in the cds.requires.API_BUSINESS_PARTNER object after “model” put a comma and add the following:
    "credentials": {
      "url": "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER/"
    }
    ​

    It should look like this:

  3. In the /srv folder create a file named address-manager-service.js. It must have the exact same name as the sibling .cds service file. In that file paste the following code:
    const cds = require('@sap/cds');
    
    //here is the service implementation
    //here are the service handlers
    module.exports = cds.service.impl(async function () {
    
        //these are the entities from address-manager-service.cds file
        const { BusinessPartners, BusinessPartnerAddresses } = this.entities;
    
        //cds will connect to the external service API_BUSINESS_PARTNER
        //which is declared in package.json in the cds requires section
        const service = await cds.connect.to('API_BUSINESS_PARTNER');
    
        //this event handler is triggered when we call
        //GET http://localhost:4004/address-manager/BusinessPartners
        this.on('READ', BusinessPartners, async (req) => {
            try {
                const tx = service.transaction();
    
                //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                let entity = 'A_BusinessPartner';
                //columns which we have declared in cds entity that we want to expose
                let columnsToSelect = ["BusinessPartner", "FirstName", "LastName"];
    
                return await tx.emit({
                    query: SELECT.from(entity)
                        .columns(columnsToSelect),
                    //For API Business Hub usage, we send custom APIKey header
                    headers: {
                        "APIKey": process.env.S4_APIKEY
                    }
                })
    
            } catch (err) {
                req.reject(err);
            }
        });
    
        //this event handler is triggered when we call
        //GET http://localhost:4004/address-manager/BusinessPartnerAddresses
        this.on('READ', BusinessPartnerAddresses, async (req) => {
            try {
                const tx = service.transaction();
    
                //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                let entity = 'A_BusinessPartnerAddress';
                //columns which we have declared in cds entity that we want to expose
                let columnsToSelect = ["BusinessPartner", "AddressID", "Country", "PostalCode", "CityName", "StreetName", "HouseNumber"];
    
                return await tx.emit({
                    query: SELECT.from(entity)
                        .columns(columnsToSelect),
                    //For API Business Hub usage, we send custom APIKey header
                    headers: {
                        "APIKey": process.env.S4_APIKEY
                    }
                })
    
            } catch (err) {
                req.reject(err);
            }
        });
    
    });
  4. Since we are reading the APIKey from environment variables we need to declare in Terminal by running:
    $env:S4_APIKEY=">>>YOUR API KEY<<<"​
  5. Go to API Business Hub, Log In, go in the Business Partner A2X, click on Show API Key and copy the value. Paste it between the double quotes and press Enter.
    $env:S4_APIKEY="8JLQURhRAeEH8OHgXFTXcfmW6H0vrW5V”​
  6. Start the app by running: npm start in the Terminal. When you access http://localhost:4004 and go to http://localhost:4004/address-manager/BusinessPartners instead of the mock data you will see data from API Business Hub sandbox.

Configure, build and deploy on SAP Cloud Platform

Steps to follow:

  1. We will be using a Destination to access the SAP S/4HANA Cloud system. For accessing that Destination configuration, we need an Authorization & Trust Management (XSUAA) and a Destination service instance to be bound to the deployed application.
  2. Go to your SAP Cloud Platform subaccount to create the Destination configuration. At subaccount level, expand Connectivity and click on Destinations. Then Click on New Destination. Use the URL to the Business Partner OData Service: https://my306116-api.s4hana.ondemand.com/sap/opu/odata/sap/API_BUSINESS_PARTNER. For User and Password use the communication user and password.
  3. Now open package.json file and change the “credentials” object to:
    "credentials": {
      "destination": "s4hc"
    }
  4. Since we will be using the the SAP S/4HANA Cloud Destination to read Business Partners, we do not need to send custom headers anymore. This means that we can change tx.emit() to tx.run() and delete the headers object and put the query directly inside. Go in the address-manager-service.js file and make these changes:
    const cds = require('@sap/cds');
    
    //here is the service implementation
    //here are the service handlers
    module.exports = cds.service.impl(async function () {
    
        //these are the entities from address-manager-service.cds file
        const { BusinessPartners, BusinessPartnerAddresses } = this.entities;
    
        //cds will connect to the external service API_BUSINESS_PARTNER
        //which is declared in package.json in the cds requires section
        const service = await cds.connect.to('API_BUSINESS_PARTNER');
    
        //this event handler is triggered when we call
        //GET http://localhost:4004/address-manager/BusinessPartners
        this.on('READ', BusinessPartners, async (req) => {
            try {
                const tx = service.transaction();
    
                //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                let entity = 'A_BusinessPartner';
                //columns which we have declared in cds entity that we want to expose
                let columnsToSelect = ["BusinessPartner", "FirstName", "LastName"];
    
                return await tx.run(
                    SELECT.from(entity)
                        .columns(columnsToSelect)
                )
    
            } catch (err) {
                req.reject(err);
            }
        });
    
        //this event handler is triggered when we call
        //GET http://localhost:4004/address-manager/BusinessPartnerAddresses
        this.on('READ', BusinessPartnerAddresses, async (req) => {
            try {
                const tx = service.transaction();
    
                //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                let entity = 'A_BusinessPartnerAddress';
                //columns which we have declared in cds entity that we want to expose
                let columnsToSelect = ["BusinessPartner", "AddressID", "Country", "PostalCode", "CityName", "StreetName", "HouseNumber"];
    
                return await tx.run(
                    SELECT.from(entity)
                        .columns(columnsToSelect)
                )
    
            } catch (err) {
                req.reject(err);
            }
        });
    
    });​
  5. The XSUAA service instance uses a xs-security.json file for configuration. Generate this file by running in the Terminal the command: cds srv –to xsuaa > xs-security.json. This will create the file in the root folder.
  6. The application will be deployed as a Multi Target Application so that we can also create the services when doing this. To add the configuration file for the deployment, run in Terminal: cds add mta
  7. Open the mta.yaml file which was generated by cds and add the following lines. Be very careful with the indentation/spaces/tabs in the .yaml file as it is very sensible.
       requires:
         - name: uaa
         - name: dest
    
    resources:
    - name: uaa
      type: org.cloudfoundry.managed-service
      parameters:
        path: ./xs-security.json
        service: xsuaa
        service-name: my-uaa
        service-plan: application
    - name: dest
      type: org.cloudfoundry.managed-service
      parameters:
        service: destination
        service-name: my-dest
        service-plan: lite
  8. Open the package.json file and add the following scripts:
    "build": "mbt build -p=cf --mtar=AddressManager.mtar",
    "deploy": "cf deploy mta_archives/AddressManager.mtar"
  9. Open a Terminal and run the script: npm run build. This will take some time. When it is finished you can see a file under /mta_archives/AddressManager.mtar. This file will be used in the deployment.
  10. Log in to your space by running in Terminal: cf login.
  11. Run the script: npm run deploy. This will also take a while. But it will take care of deploying the app, creating the service instances and binding them to the app.
  12. You can now go to SAP Cloud Platform and access your app URL to see the app which is exposing SAP S/4HANA Cloud data.
  13. You can use the deployed application’s information when starting the local application. To do that start by creating a file in the root project folder with the name default-env.json with the following contents:
    {
        "VCAP_SERVICES": {…},
        "VCAP_APPLICATION": {…}
    }​
  14. Then run in Terminal the command: cf env cap-adman-srv and copy the values of VCAP_SERVICES and VCAP_APPLICATION in your default-env.json. Be careful to put in the correct format. Now run npm start. Go to http://localhost:4004 and you will see the data like in the deployed app.
  15. Let’s introduce also cds watch which will automatically detect changes. Go to package.json and add the following script:
    "watch": "npx cds watch"​
  16. Go also in the launch.json file and add a watch configuration like this:
    {
      "command": "cds watch",
      "name": "cds watch",
      "request": "launch",
      "type": "node-terminal",
      "skipFiles": [
        "<node_internals>/**"
      ]
    }
    ​

    You can also delete the env variable as we are now reading from the SAP S/4HANA Cloud system using the Destination.

Add OData V2 adapter and READ one entity

Steps to follow:

  1. In the /srv folder create a file server.js and paste the following code inside it:
    const proxy = require('@sap/cds-odata-v2-adapter-proxy')
    const cds = require('@sap/cds')
    cds.on('bootstrap', app => app.use(proxy()))
    module.exports = cds.server
  2. Open a Terminal and run: npm install @sap/cds-odata-v2-adapter-proxy –save
  3. Start your application with npm run watch. Access http://localhost:4004/address-manager/ which serves OData V4 and try to add /v2/ in the endpoint like this http://localhost:4004/v2/address-manager/ which servers OData V2. We will need the OData V2 service in the UI.
  4. We implemented a handler which READs all the BusinessPartners, but if we try http://localhost:4004/v2/address-manager/BusinessPartners(‘1000000’) this will not work yet because it is missing the JavaScript implementation for this. Go to address-manager-service.js and modify the code like this:
    const cds = require('@sap/cds');
    
    //here is the service implementation
    //here are the service handlers
    module.exports = cds.service.impl(async function () {
    
        //these are the entities from address-manager-service.cds file
        const { BusinessPartners, BusinessPartnerAddresses } = this.entities;
    
        //cds will connect to the external service API_BUSINESS_PARTNER
        //which is declared in package.json in the cds requires section
        const service = await cds.connect.to('API_BUSINESS_PARTNER');
    
        //this event handler is triggered when we call
        //GET http://localhost:4004/address-manager/BusinessPartners
        this.on('READ', BusinessPartners, async (req) => {
            try {
                const tx = service.transaction();
    
                //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                let entity = 'A_BusinessPartner';
                //columns which we have declared in cds entity that we want to expose
                let columnsToSelect = ["BusinessPartner", "FirstName", "LastName"];
    
                //if there is a parameter
                if (req.params[0]) {
                    //If you look in the .csn file you will see that
                    //the key for our BusinessPartner entity is BusinessPartner column
                    const businessPartner = req.params[0].BusinessPartner;
                    return await tx.run(
                        SELECT.from(entity)
                            .columns(columnsToSelect)
                            .where({ 'BusinessPartner': businessPartner })
                    )
                } else {
                    //if no parameter, we read all Business Partners
                    return await tx.run(
                        SELECT.from(entity)
                            .columns(columnsToSelect)
                    )
                }
    
            } catch (err) {
                req.reject(err);
            }
        });
    
        //this event handler is triggered when we call
        //GET http://localhost:4004/address-manager/BusinessPartnerAddresses
        this.on('READ', BusinessPartnerAddresses, async (req) => {
            try {
                const tx = service.transaction();
    
                //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                let entity = 'A_BusinessPartnerAddress';
                //columns which we have declared in cds entity that we want to expose
                let columnsToSelect = ["BusinessPartner", "AddressID", "Country", "PostalCode", "CityName", "StreetName", "HouseNumber"];
    
                //if there is parameter
                if (req.params[0]) {
                    //If you look in the .csn file you will see that
                    //the keys for our BusinessPartnerAddress entity are
                    //BusinessPartner and AddressID columns
                    const businessPartner = req.params[0].BusinessPartner;
                    const addressId = req.params[0].AddressID;
                    return await tx.run(
                        SELECT.from(entity)
                            .columns(columnsToSelect)
                            .where({
                                'BusinessPartner': businessPartner,
                                'AddressID': addressId
                            })
                    )
                } else {
                    //if no parameter, we read all Business Partner Addresses
                    return await tx.run(
                        SELECT.from(entity)
                            .columns(columnsToSelect)
                    )
                }
    
            } catch (err) {
                req.reject(err);
            }
        });
    
    });​
  5. Start the app from Debug panel in watch mode, put some breakpoints and look at the execution of the code while you access:

Lessons learned

During the development, the part with sending the APIKey needed some research because I initially did not know how to do it. I finally found the solution in this GitHub repository with questions and issues about CAP which I find extremely helpful when you are trying to learn how to use CAP because there you can find lots of answers and solutions.

Final words

Now you know how to:

  • develop the CAP application
  • configure, build & deploy to SAP Cloud Platform

Before starting the implementation of the app, I looked for a blog post that covers this technical scenario but I only found some which were similar and extremely helpful to me, so I will mention them and express many thanks to the authors:

Please feel free and I highly encourage anyone to share more knowledge about this topic or suggest better ways, give feedback and contribute to building a starter scenario for extension applications using JavaScript.

Part 2 is published

In the second part I will cover how to:

  • add Create, Update, Delete service handlers using SAP Cloud SDK
  • generate a Fiori app using Fiori Tools
  • add annotations in the CAP application

Assigned Tags

      21 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Martin Stenzig
      Martin Stenzig

      Great blog, looking forward to the remaining pieces.

      The GitHub repo you referenced under lessons learned is unfortunately not available to us non-SAP'ers 🙂 Would you mind sharing the content or at least the bits that helped you?

      Author's profile photo Ioana Stefania Santimbrean
      Ioana Stefania Santimbrean
      Blog Post Author

      Thank you, Martin!

      An alternative for the GitHub repo is here in the SAP Community: the questions tagged with SAP Cloud Application Programming Model. The GitHub repo is also a place to ask questions and see answers.

      I was looking for a way to send the APIKey. I browsed other questions and found that you can use tx.emit() instead of tx.run(). Like you see best answer to this question.

      After that I found the reference to this also in the documentation.

      I wanted to point out this difference, that's why at Configure, build and deploy on SAP Cloud Platform, step 4 when we switch to using a Destination I changed also from tx.emit() to tx.run().

      I hope this helps 🙂

      Kind regards,

      Stefania

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Martin,

      for a working example of what Ioana showed here check out my example repository epmbp-consumer-app. I've also just updated it to get the API Key from external.

      Best regards
      Gregor

      Author's profile photo Luisa Grigorescu
      Luisa Grigorescu

      Great blog post Stefi! Thanks for your effort. 🙂

      Author's profile photo Ioana Stefania Santimbrean
      Ioana Stefania Santimbrean
      Blog Post Author

      Thank you, Luisa 🙂

      Author's profile photo poruri rama pavani
      poruri rama pavani

      hi,

       

      Thanks for the blog, i am trying the same, but getting below issue:

      <error xmlns="http://docs.oasis-open.org/odata/ns/metadata">
      <code>500</code>
      <message>No credentials configured for "undefined"</message>
      <annotation term="Common.numericSeverity" type="Edm.Decimal">4</annotation>
      </error>
      i am passing APIKey in .js code itself:
      return await tx.emit({
                      query: SELECT.from(entity)
                           .columns(columnsToSelect),
                      // //For API Business Hub usage, we send custom APIKey header
                      headers: {
                          "APIKey": 'LkQEZ9AaCw1GZ3kwddersTtAF0wjm3nI'
                      }
                  })
      can you please help here?
      Regards,
      Rama

       

       

      Author's profile photo Ioana Stefania Santimbrean
      Ioana Stefania Santimbrean
      Blog Post Author

      Hello Rama,

      I have not encountered this error before. Can you try to test the API with Postman with this APIKey and see if it works?

      Also could you share if your cds entities are defined in the same way and if you are using Business Partner API?

      Best regards,

      Stefania

      Author's profile photo Saurav Mehta
      Saurav Mehta

      Hi Pavani,

      Instead of writing "await tx.emit()" you can write "await tx.send()"

       

      The send() function, is used for making requests to external services or APIs. It's often used when you need to retrieve data from an external source or send data to an external service.

       

      Thank you

      Author's profile photo poruri rama pavani
      poruri rama pavani

      Thanks for the quick reply.

      I tested it from postman and got output using same APIKey.

      i am using business application studio to develop this.

      and i used the  same code which you have mentioned and only difference is i have passed APIKey directly in .js file code as mentioned below :

       

      const cds = require('@sap/cds');
      // const proxy = require("@sap/cds-odata-v2-adapter-proxy");
      // cds.on("bootstrap", app => app.use(proxy()));
      //here is the service implementation
      //here are the service handlers
      module.exports = cds.service.impl(async function () {
          //these are the entities from address-manager-service.cds file
          const { BusinessPartners, BusinessPartnerAddresses } = this.entities;
          //cds will connect to the external service API_BUSINESS_PARTNER
          //which is declared in package.json in the cds requires section
          const service = await cds.connect.to('API_BUSINESS_PARTNER');
          //this event handler is triggered when we call
          //GET http://localhost:4004/address-manager/BusinessPartners
          this.on('READ', BusinessPartners, async (req) => {
              try {
                  const tx = service.transaction();
                  //entity name as it is in the .csn file for the service API_BUSINESS_PARTNER
                  let entity = 'A_BusinessPartner';
                  //columns which we have declared in cds entity that we want to expose
                  let columnsToSelect = ["BusinessPartner", "FirstName", "LastName"];
                  return await tx.emit({
                      query: SELECT.from(entity)
                           .columns(columnsToSelect),
                      // //For API Business Hub usage, we send custom APIKey header
                      headers: {
                          "APIKey": 'LkQEZ9AaCw1GZ3kwddersTtAF0wjm3nI'
                      }
                  })
              } catch (err) {
                  req.reject(err);
              }
          });
      Author's profile photo poruri rama pavani
      poruri rama pavani

      Hi Experts,

      Really appreciate your help here, to resolve the above error?

      Regards,

      Rama

       

      Author's profile photo Navneet Kaur
      Navneet Kaur

      Hi Ioana,

      Thanks for sharing the blog.

      I have implemented business Partner API in CAP. However, we have a requirement wherein we will have to use navigation property, to_BuPaIndustry.

       

      service MasterDataService @(path:'/masterdata'){
          @readonly
          entity BusinessPartners as projection on externalBP.A_BusinessPartner {
              BusinessPartner, LastName, FirstName, BusinessPartnerFullName,BusinessPartnerCategory
          };

       

      While running with $expand to_BuPaIndustry, I am getting the below error:
      Navigation property 'to_BuPaIndustry' is not defined in type 'MasterDataService.BusinessPartners'
      Could you please guide me on how can we make it run?
      Regards,
      Navneet
      Author's profile photo Stefania Santimbrean
      Stefania Santimbrean

      Hello Navneet,

      Your entity in .cds file should contain also the navigation like this:

      service MasterDataService @(path:'/masterdata'){
          @readonly
          entity BusinessPartners as projection on externalBP.A_BusinessPartner {
              BusinessPartner, LastName, FirstName, BusinessPartnerFullName,BusinessPartnerCategory, to_BuPaIndustry
          };
      };

      And if I remember corectly you might need to also to implement the expand in the service handler (.js file).

      Hope this helps 🙂

      Kind regards,

      Stefania

      Author's profile photo Former Member
      Former Member

      Hi Ioanna,

      Thanks for this great tutorial!

      I am getting an error when trying to deploy the app on cf. Xsuaa service cannot be created because fields "$version" and "definitions" in xs-security.json are unrecognized, and not marked as ignorable.

      I instead used cds compile srv/ --to xsuaa > xs-security.json and it worked fine.

      Perhaps you can help the error and explain what's the difference between these two commands.

       

      Best,

      Thymios

      Author's profile photo Stefania Santimbrean
      Stefania Santimbrean

      Hello Thymios,

      I think it was a mistake from my side, probably forgot to write the "compile". Thanks for your comment and pointing it out!

      Regards,

      Stefania

      Author's profile photo Former Member
      Former Member

      Hi Stefania,

      Thanks a lot for your answer regarding xs-security.json. I have another one about connecting to a remote system from local application using the VCAP env variables 🙂

      I have created the default-env.json and pasted the VCAP json from CF, but when running npm start I get a connection time out error (Error during request to remote service: connect ETIMEDOUT).

      Please note that I am trying to connect to an On Premise S4H system. It works fine if I run the deployed app on CF.

      Any ideas why this is happening?

       

      Thanks,

      T

       

      Author's profile photo Stefania Santimbrean
      Stefania Santimbrean

      Hello Tim,

      Since you are connecting to an On-Premise system you probably have already created a Destination and you have a Cloud Connector set up in your subaccount in BTP. This means your deployed app has bindings to XSUAA, Destination and Connectivity services.

      On local you are missing that secure tunnel to your On-Premise system. What you can do to create it is to enable your deployed app for SSH and create a SSH connection with port forwaring.

      The process is described here: https://sap.github.io/cloud-sdk/docs/java/features/connectivity/sdk-connectivity-destination-service/#enable-access-to-sap-business-technology-platform-connectivity-service

      Let me know if you managed to make it work 🙂

      Regards,

      Stefania

       

      Author's profile photo Former Member
      Former Member

      Hi Stefania,

      Thanks a lot for sharing the link, I did not think to look under Java in the documentation 🙂 .

      Yep, cloud connector, connectivity and destination are all set up and work fine when I run the app in cf.

      I followed the instructions but unfortunately getting a new error now:

      Error during request to remote service: Failed to build HTTP request for destination: failed to load destination!

      Best,

      Thymios

       

      Author's profile photo Stefania Santimbrean
      Stefania Santimbrean

      Hello Thymios,

      Are you using SAP Cloud SDK in the service handlers or are you using CAP external service consumption?

      I assume it’s SAP Cloud SDK and I see here a description on how you can set up a local destination for development: https://sap.github.io/cloud-sdk/docs/js/features/connectivity/proxy#what-kind-of-proxies-are-there

      As far as I know SAP Cloud SDK does not read default-env.json files like CAP does.

      Hope it helps,

      Stefania

      Author's profile photo Former Member
      Former Member

      Hi Stefania,

      I am using CAP in the service handlers.

      Tried to play around with the default-env.json and port forwarding command but still no luck.

      Best,

      Thymios

      Author's profile photo Former Member
      Former Member

      Hi Stefania,

      Sorry, mistake on my side. Updated the default-env.json with VCAP variables and it worked fine.

      Many thanks for your time helping out and again for this great tutorial!

      Best,

      Thymios 🙂

      Author's profile photo Gregor Wolf
      Gregor Wolf

      Hi Stefania,

      please check out jowavp/sap-cf-proxy for an integrated solution.

      Best regards
      Gregor