Skip to Content
Technical Articles
Author's profile photo Marius Obert

Using the Destination service in SAP BTP, Cloud Foundry Environment

In this blog post, I will briefly explain why there are ‘destinations’ in SAP BTP, Cloud Foundry. I will also show some hands-on examples of how to consume them.

Leveraging existing services and data sources is the core of each cloud-based business application out there. Connecting applications to those destinations is a very crucial element of your application and should be done the right way. SAP BTP recognized the importance of this element and offers with the destination service a scalable solution in the Cloud Foundry Environment.

To keep this post as simple as possible, I won’t dive into the SAP Cloud Connector or the SAP Connectivity Service, which is a proxy service to redirect requests to on-premise systems (I recommend this blog post if you’re interested in this scenario).

Updates:

19th Nov 2020 – Refresh GIFs

29th Jan 2021: Rebranding to SAP BTP

9th Jan 2021: Add video tutorial to test destinations

Why do I need destinations?

I think all of us agree that it would be easiest to hardcode the destination information into the codebase. But this (rookie) mistake has several issues, just to name a few:

  1. Re-usability

You would need to copy and paste the same information into several modules/apps when you want to re-use it (=> Antipattern)

  1. Standardized form

Closely related to the re-usability aspect, you need to come up with a standardized format (e.g. do you prefer the properties ‘protocol’, ‘hostname’, ‘port’ or would you rather combine them to ‘URL’?). It’s crucial to enforce this format across all destinations

  1. Sensitive information in the codebase

Never ever (ever!) add sensitive information, such as passwords, to your code! I think I don’t need to explain this one

  1. Need to handle various authentication strategies

Authentication strategies vary access different destinations types and you need to implement each single one

  1. Integration with development tools

Dev tools (like code generators) have virtually no use if they cannot access supporting information

How can I make sure my destinations are set up correctly?

I recorded a short video tutorial that you can follow to make sure your destination is working as expected. Do you know your destination is already accessible? Then jump ahead to the next section.

Watch%20the%20video%20on%20YouTube

Watch the video on YouTube

How does this translate to the “Cloud Foundry world”?

The previous section did not only show that information about the endpoints should be stored centrally, but it also showed that there is a need for “business logic” to consume it.

In general, applications shouldn’t be hardwired to resources (like text files or database systems), but be rather coupled loosely to them. Backing services are the best practice to couple resources to applications running in Cloud Foundry environments. Therefore, SAP encapsulates the necessary business logic and the persistence layer for those tasks and makes it easy to consume as a backing service (Destination service).

Your application can access the destinations via a so-called (Destination) service instance.

Using the destinations-service in the backend

There are three steps to enable a backend application to access destinations

  1. Enter the information for the destination

I recommend that you enter them on the subaccount level in the Cloud Foundry environment (it’s also possible to add them on the service instance level).

  1. Create a destinations service instance

This service is able to read and transmit the information you stored in the previous step it securely.

  1. Create an xsuaa service instance

This service issues a JWT token to authenticate to the destinations service instance.

Same as the previous step, just filter the marketplace for “trust” instead.

My colleague Matthieu Pelatan has described this process of retrieving the destination information very detailed in a mini-blog-series (Part 1, Part 2, Part 3). Therefore, I would like to keep this section rather short and simply list the necessary steps here:

  1. Read required the environment variables
  2. Use the retrieved values to request a JWT access token (for the destinations service instance) from the UAA
  3. Get the destination details from the destination service instance
  4. Request the resource behind your destination!

 

The official documentation contains nice code samples for Java and your terminal (curl), so instead, I thought I’d supply some code in JavaScript and Python.

Node.js [JavaScript]

This snippet uses the npm package request, which can be substituted with a module of your choice.

 

const request = require('request');
const cfenv = require('cfenv');

/*********************************************************************
 *************** Step 1: Read the environment variables ***************
 *********************************************************************/
const oServices = cfenv.getAppEnv().getServices();
const uaa_service = cfenv.getAppEnv().getService('uaa_service');
const dest_service = cfenv.getAppEnv().getService('destination_service');
const sUaaCredentials = dest_service.credentials.clientid + ':' + dest_service.credentials.clientsecret;

const sDestinationName = 'scp';
const sEndpoint = '/secure/';

/*********************************************************************
 **** Step 2: Request a JWT token to access the destination service ***
 *********************************************************************/
const post_options = {
    url: uaa_service.credentials.url + '/oauth/token',
    method: 'POST',
    headers: {
        'Authorization': 'Basic ' + Buffer.from(sUaaCredentials).toString('base64'),
        'Content-type': 'application/x-www-form-urlencoded'
    },
    form: {
        'client_id': dest_service.credentials.clientid,
        'grant_type': 'client_credentials'
    }
}

request(post_options, (err, res, data) => {
    if (res.statusCode === 200) {

        /*************************************************************
         *** Step 3: Search your destination in the destination service ***
         *************************************************************/
        const token = JSON.parse(data).access_token;
        const get_options = {
            url: dest_service.credentials.uri + '/destination-configuration/v1/destinations/' + sDestinationName,
            headers: {
                'Authorization': 'Bearer ' + token
            }
        }

        request(get_options, (err, res, data) => {

            /*********************************************************
             ********* Step 4: Access the destination securely *******
             *********************************************************/
            const oDestination = JSON.parse(data);
            const token = oDestination.authTokens[0];

            const options = {
                method: 'GET',
                url: oDestination.destinationConfiguration.URL + sEndpoint,
                headers: {
                    'Authorization': `${token.type} ${token.value}`
                }
            };

            request(options).on('data', (s) => {
                console.log(s.toString())
            });
        });
    }
});

Python

SAP recently announced that the Python runtime is officially supported now! So, I would like to take this as an occasion to include a python script here:

from cfenv import AppEnv
import requests
import base64


######################################################################
############### Step 1: Read the environment variables ###############
######################################################################

env = AppEnv()
uaa_service = env.get_service(name='uaa_service')
dest_service = env.get_service(name='destination_service')
sUaaCredentials = dest_service.credentials["clientid"] + ':' + dest_service.credentials["clientsecret"]
sDestinationName = 'scp'

######################################################################
#### Step 2: Request a JWT token to access the destination service ###
######################################################################

headers = {'Authorization': 'Basic '+base64.b64encode(sUaaCredentials), 'content-type': 'application/x-www-form-urlencoded'}
form = [('client_id', dest_service.credentials["clientid"] ), ('grant_type', 'client_credentials')]

r = requests.post(uaa_service.credentials["url"] + '/oauth/token', data=form, headers=headers)

######################################################################
####### Step 3: Search your destination in the destination service #######
######################################################################

token = r.json()["access_token"]
headers= { 'Authorization': 'Bearer ' + token }

r = requests.get(dest_service.credentials["uri"] + '/destination-configuration/v1/destinations/'+sDestinationName, headers=headers)

######################################################################
############### Step 4: Access the destination securely ###############
######################################################################

destination = r.json()
token = destination["authTokens"][0]
headers= { 'Authorization': token["type"] + ' ' + token["value"] }

r = requests.get(destination["destinationConfiguration"]["URL"] + '/secure/', headers=headers)
print(r.text)

Please note that you need to declare the modules “request” and “cfenv” to your app via a requirements.txt file before deploying the code.

 

Using the destination service in the frontend (= SAPUI5 web apps)

Apart from the reasons above, there is one additional reason why you want to have a destination service for web apps:

Same Origin Policy

I’m sure every web dev out there cursed this mechanism at least once in his/her life. For the “lucky” ones of you who didn’t have to deal with SOP before: It is a security mechanism of your browser that basically blocks all requests your client-side script sends to any web server, except the webserver which delivered this script.

The most common workaround is sending a request to your web server, which proxies the request to the final destination. With the SAP Application Router, on the other side, you don’t need to bother at all! The router knows how to access the destination out-of-box. You don’t need to request a JWT token from the XSUAA service instance and you don’t need to request the destination information from the destinations-service. You don’t even have to implement the authentication strategy. SAP Application Router takes care of all that for you. 

Here’s what you have to do in the SAPUI5 application:

 

  1. Enter the information for the destination

I recommend that you enter them on the subaccount level in the Cloud Foundry environment (it’s also possible to add them on the service instance level).

 

 

  1. The SAP Business Application Studio should create those resources and bindings by default. Make sure both services are defined (“resources” section) and bound to the app (“requires” section) in the mta.yml file:
resources:
 - name: uaa_service
   parameters:
      path: ./xs-security.json
      service-plan: application
      service: xsuaa
   type: org.cloudfoundry.managed-service

 - name: destination_service
   parameters:
      service-plan: lite
      service: destination
   type: org.cloudfoundry.managed-service
  1. Add the route to the destination in the file xs-app.json. This descriptor file tells the web server how the requests need to be proxied to the respective destination:
"routes": [{
	  "source": "^/scp/(.*)",
	  "target": "/$1",
	  "destination": "scp"
}...
  1. Call endpoint from the application
$.get('/scp/secure').then((sMsg)=>{alert(sMsg)});

Conclusion

There are many good reasons why you should use destinations in the Cloud Foundry, ABAP, and Kubernetes environment, such as preventing the use of anti-patterns, storing your credentials in a safe place (in general just to make your life easier). At first sight, the process of retrieving those destinations in your application might seem confusing. I hope this article could shed some light on this process and prove that’s it’s actually quite simple.

Assigned Tags

      119 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Gini Hu
      Gini Hu

      Hi Marius Obert ,

      For python example, how to connect a destination with authentication type 'PrincipalPropagation' ? It doesn't have a property called 'authTokens'.

      Thanks!

       

      Best regards,

      Gini

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Gini,

      sorry for the late response. I have to say I'm not very familiar with principle propagation yet, but let's try to solve this puzzle together!

      Yes, you are right, there is no authTokens field (due to the nature of principle propagation). This blog post was focussing on the destination service (e.g. it only retrieved the information you entered in the SAP Cloud Platform Cockpit).

      In your case, you need to utilize the Connectivity service as well (You can think of it as a proxy in the cloud platform which redirect your request via the secure tunnel to your backend system). My colleague Matthieu Pelatan has written a very good blog post about the mechanics of this service and how to use it (in Java).

      You can follow his steps from 4b on to connect to the connectivity service and to send the request to the proxy. Please be aware that he refers to the value

      'Basic '+base64.b64encode(sUaaCredentials)

      with JWT1 and to

      'Bearer ' + token 

      with JWT2.

      So your first steps are (besides configuring the backend as described by Matthieu):

      1. Create a destination service instance and bind it to your app
      2. Request JWT3 to access this service instance
      3. Invoke the service instance as a proxy

      Regards,

      Marius

      Author's profile photo Gini Hu
      Gini Hu

      Hi Marius,

      You're correct, use the connectivity instance as a proxy, with JWT3 and sUaaCredentials, it works finally! Thank you very much for your help!

      Best regards,

      Gini

      Author's profile photo Jiani Zhang
      Jiani Zhang

      Hi Gini, can you please help to provide sample code for this? I still cannot figure this out. Thank you in advance.

      Author's profile photo Maveric Ramos
      Maveric Ramos

      So, how do i call the services ODATA since my node js code?

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Maveric,

      you can use the described pattern to send requests to odata endpoints as well (since those are also just HTTP(S) requests). It might make sense to use an npm package to abstract the way the URL is assembled.

      You can find some packages here or on npm. Please make sure to pick a package which allows you to add a custom header for the auth token

      Author's profile photo Rossano Rosica
      Rossano Rosica

      Hi Marius,

      first of all thanks for your great post. I have a scenario with a MTA project with 3 simple modules: db, nodejs and UI5. From the UI5 module I would consume some destinations setted inside a destination service instance in CF-Trial.

      This is my mta.yaml:

      ID: journeybook
      _schema-version: '2.1'
      version: 0.0.1
      modules:
        - name: journeybookdb
          type: hdb
          path: journeybookdb
          requires:
            - name: hdi_journeybookdb
        - name: journeybookruntime
          type: nodejs
          path: journeybookruntime
          provides:
            - name: journeybookruntime_api
              properties:
                url: '${default-url}'
          requires:
            - name: hdi_journeybookdb
            - name: journeybookdb
            - name: journeybook_uaa
        - name: journeybookui
          type: html5
          path: journeybookui
          parameters:
            disk-quota: 512M
            memory: 512M
          build-parameters:
            builder: grunt
          requires:
            - name: uaa_journeybook
            - name: dest_journeybook
      
      resources:
        - name: hdi_journeybookdb
          properties:
            hdi-container-name: '${service-name}'
          type: com.sap.xs.hdi-container
      
        - name: journeybook_uaa
          type: com.sap.xs.uaa
      
        - name: uaa_journeybook
          parameters:
            path: ./xs-security.json
            service-plan: application
            service: xsuaa
          type: org.cloudfoundry.managed-service
      
        - name: dest_journeybook
          parameters:
            service-plan: lite
            service: destination
          type: org.cloudfoundry.managed-service
      

      In the destination service I set up one Northwind destination called "northwind" and then in xs-app.json I set up the destination as:

      {
        "welcomeFile": "/journeybookui/index.html",
        "authenticationMethod": "route",
        "logout": {
          "logoutEndpoint": "/do/logout"
        },
        "routes": [
          {
            "source": "^/journeybookui/(.*)$",
            "target": "$1",
            "localDir": "webapp"
          },
          {
          	"source": "/northwind/(.*)",
          	"destination": "northwind"
          }
        ]
      }

      When I "Run as Web Application" on Cloud Foundry from WebIDE I receive a 404 error and on CF-Trial Applications section I see that this UI module is in "CRASHED" status. Without "northwind" destination in xs-app all works fine.

      Could you help me?

      Thanks,
      Rossano

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Rossano,

      sorry for the inconvenience, this obviously shouldn't happen.

      Tbh, I'm not sure if bound services are already supposed to work when you "run" the webapp. As you might know, the "run on CF" feature is only a couple of days old and therefore it is likely that there are still some issues.

      Can you build the archive and deploy it to CF and then try it again? It would be good to know if this issue is related to the new feature or the code/config.

      Thanks,

      Marius

      Author's profile photo Rossano Rosica
      Rossano Rosica

      Hi Marius and thanks for your response,

      if I build the app with "northwind" in xs-app I receive this response:

      16:16:13 (Builder) Build of "/journeybook" started.
      16:16:18 (DIBuild) Build of "/journeybook" in progress.
      16:16:18 (DIBuild) [INFO] Target platform is CF[INFO] Reading mta.yaml[INFO] Processing mta.yaml[INFO] Processing module journeybookdb
      16:16:23 (DIBuild) [INFO] Logs of build task for module journeybookdb:>  [INFO] Injecting source code into builder...>  [INFO] Source code injection finished>  [INFO] ------------------------------------------------------------------------>  Your module contains a package.json file, it will be used for the build.>  added 37 packages from 79 contributors in 2.371s[INFO] Processing module journeybookruntime
      16:16:40 (DIBuild) [INFO] Logs of build task for module journeybookruntime:>  [INFO] Injecting source code into builder...>  [INFO] Source code injection finished>  [INFO] ------------------------------------------------------------------------>  npm ERR! cb() never called!>  >  npm ERR! This is an error with npm itself. Please report this error at:>  npm ERR!     <https://github.com/npm/npm/issues>[INFO] Processing module journeybookui[ERROR] Failed to build module journeybookruntime.
      16:16:43 (Builder) Build of /journeybook failed.

      if I build the app without "northwind" in xs-app I receive this response:

      16:11:30 (Builder) Build of "/journeybook" started.
      16:11:36 (DIBuild) Build of "/journeybook" in progress.
      16:11:36 (DIBuild) [INFO] Target platform is CF[INFO] Reading mta.yaml[INFO] Processing mta.yaml[INFO] Processing module journeybookdb
      16:11:39 (DIBuild) [INFO] Logs of build task for module journeybookdb:>  [INFO] Injecting source code into builder...>  [INFO] Source code injection finished>  [INFO] ------------------------------------------------------------------------>  Your module contains a package.json file, it will be used for the build.>  added 37 packages from 79 contributors in 2.64s
      16:11:42 (DIBuild) [INFO] Processing module journeybookruntime
      16:12:05 (DIBuild) [INFO] Logs of build task for module journeybookruntime:>  [INFO] Injecting source code into builder...>  [INFO] Source code injection finished>  [INFO] ------------------------------------------------------------------------>  >  > @sap/fibers@2.0.2-0 preinstall /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs-test/node_modules/@sap/fibers>  > node preinstall.js>  >  >  > @sap/fibers@2.0.2-0 preinstall /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/fibrous/node_modules/@sap/fibers>  > node preinstall.js>  >  >  > @sap/fibers@2.0.2-0 preinstall /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/fibers>  > node preinstall.js>  >  >  > @sap/fibers@2.0.2-0 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs-test/node_modules/@sap/fibers>  > node build.js || nodejs build.js>  >  `linux-x64-LE-57` exists; testing>  Binary is fine; exiting>  >  > @sap/fibers@2.0.2-0 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/fibers>  > node build.js || nodejs build.js>  >  `linux-x64-LE-57` exists; testing>  Binary is fine; exiting>  >  > @sap/fibers@2.0.2-0 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/fibrous/node_modules/@sap/fibers>  > node build.js || nodejs build.js>  >  `linux-x64-LE-57` exists; testing>  Binary is fine; exiting>  >  > @sap/node-jwt@1.4.8 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/node-jwt>  > node ./build.js>  >  `linux-x64-v8-6.1` exists; testing>  Binary is fine; exiting>  >  > @sap/node-vsi@1.4.7 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/node-vsi>  > node ./build.js>  >  `linux-x64-v8-6.1` exists; testing>  Binary is fine; exiting>  >  > @sap/node-jwt@1.4.8 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/sap.nodejs/builds/build-6746198426087403832/journeybookruntime/node_modules/@sap/xsjs/node_modules/@sap/xsodata/node_modules/@sap/xssec/node_modules/@sap/node-jwt>  > node ./build.js>  >  `linux-x64-v8-6.1` exists; testing>  Binary is fine; exiting>  added 545 packages from 332 contributors in 23.071s
      16:12:39 (DIBuild) [INFO] Processing module journeybookui
      16:13:22 (DIBuild) [INFO] Logs of build task for module journeybookui:>  [INFO] Injecting source code into builder...>  [INFO] Source code injection finished>  [INFO] ------------------------------------------------------------------------>  >  > @sap/node-jwt@1.4.13 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/grunt-builder-cf/builds/build-2531501618031422018/journeybookui/node_modules/@sap/node-jwt>  > node ./build.js>  >  `linux-x64-v8-6.1` exists; testing>  Binary is fine; exiting>  >  > uws@9.14.0 install /home/vcap/app/.java-buildpack/tomcat/temp/builder/grunt-builder-cf/builds/build-2531501618031422018/journeybookui/node_modules/uws>  > node-gyp rebuild > build_log.txt 2>&1 || exit 0>  >  >  > sinon@4.4.8 postinstall /home/vcap/app/.java-buildpack/tomcat/temp/builder/grunt-builder-cf/builds/build-2531501618031422018/journeybookui/node_modules/sinon>  > node scripts/support-sinon.js>  >  Have some ❤️  for Sinon? You can support the project via Open Collective:>   > https://opencollective.com/sinon/donate>  >  added 1060 packages from 1417 contributors in 36.276s>  (node:906) ExperimentalWarning: The http2 module is an experimental API.>  Running "lint" task>  >  Running "mkdir:dist" (mkdir) task>  Creating "dist"...OK>  >  Running "lint-js" task>  basevalidator attribute for js in the project.json file is: fioriJsValidator>  >  Running "lint-xml" task>  basevalidator attribute for xml in the project.json file is: fioriXmlAnalysis>  >  Running "lint-json" task>  >  Running "writeLintResults" task>  >  Done.
      16:13:48 (DIBuild) [INFO] Creating MTA archive
      16:15:12 (DIBuild) [INFO] Saving MTA archive journeybook_0.0.1.mtar
      16:15:20 (DIBuild) [INFO] Done
      16:15:20 (DIBuild) ********** End of /journeybook Build Log **********
      16:15:20 (Builder) The .mtar file build artifact was generated under /mta_archives/journeybook.
      16:15:27 (Builder) Build of /journeybook completed successfully.

      Definitely I can build and deploy only without the custom route in xs-app.

      Thanks,
      Rossano

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Rossano,

       

      is this a real-world project or do you use it to learn? In case it’s the latter, can you export the project and sent it to me via Email so I can have a look at the implementation details.

       

      EDIT: The issue was related to instance level destinations, if you run in the same issue: Please update your app router to version 5.12 or higher

       

      Thanks,

      Marius

      Author's profile photo Paige Ola
      Paige Ola

      Hi Marius Obert ,

      I have a similiar issue and I posted the question already on stackoverflow.

      Maybe you want to take a look at it:

      https://stackoverflow.com/q/55353211/10810743

      Regards,

      Paige

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Paige,

      I would comment below your SO post, but I don't have enough reputation so far, so I'll do it here.

      It looks like you're building a cloud-native scenario, which doesn't require destinations as I described them here. If I understand your problem correctly, you don't need destinations. You would only need them if you were trying to connect to a "non-cloud" or "remote cloud" endpoint.

      The app router will split the incoming traffic and send it either to your UI app or to the node server, depending on the way you configured it in the xs-app.json. It looks like your "UI route" matches all routes with "^(.*)$" and doesn't send any traffic to the node server.

      Try to change the order of the elements in the routes array

      Author's profile photo Paige Ola
      Paige Ola

      Hi Marius Obert,

      thank you for your quick answer. Unfortunately it does not work this way either. And the logs do not give any hint why.

      I understood it somehow like this: if you have i.e. an on-premise system to connect, then you need the connectivity service and the destination service. If you want to connect to another module in your mta, you only need destination service. But nowhere is explained how it works exactly.

      Somehow like in this tutorial:

      https://blogs.sap.com/2018/06/27/destination-service-on-cloud-foundry/

      Do you know an example like this, where this scenario is showed? I'd really need to fix this.

      Regards,

      Paige

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Paige,

      I can understand your confusion, I hope this (simplified) explanation helps:

      • The destinations service is basically a storage place for destinations info (URL, protocol, credentials etc) and not more
      • The connectivity service know how to authenticate, given the information stored with the dest svc (so yes, to establish a valid connection to an on-prem system you'll need both)
      • The app router is basically a "reverse proxy" (e.g. one entry point that redirects the traffic to several outputs). You can tell the app router to route all traffic to /ui/* to the UI module, all traffic to /odata/* to a node module and traffic to /onprem/* to a destination. You can redirect it to a destination but in your case, you want to send it to your module.

      In the blog you mentioned, each module is published as a separate application, which is not what I would recommend. It's easier if you bundle all modules to a mta and publish this single resource.

      You can check out this tutorial which covers basically everything that I mentioned 🙂

      Author's profile photo Paige Ola
      Paige Ola

      Hi Marius Obert,

      thank you very much for your explanation, now I’ve got it more clearly.

      What I did now was to create another mta with no html5 application repository. And there it works as expected.

      Now I found out, that the destination property is not supported for an application router in combination with an html5 application repository as described here: https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/1e0424b4e1d8441ebb245c4d1e6bb0e5.html.

      Is this really true? I added the option for a fiori launchpad portal site later and this wants the html5 repo mandatorily (as read in a sap blog and also tested). Can you use the flp then only with hana db modules? Or is there another way to request other module's api?

       

      Best regards,

      Paige

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Paige,

      it's correct that the html5 app repository doesn't support the destination property.

      In your case, this doesn't matter though. According to the code in your SO post, you aren't using the html5 app repo. You're using the app router to host your html5 module. This one does support the destination property.

      Again, you do not need destinations at all. You app router is perfectly fine and all you need to route traffic between html5, nodejs and db modules

      Author's profile photo Paige Ola
      Paige Ola

      Hi Marius Obert,

      thank you again for your explanation and your effort.

      I think I am using the html5 app repo as I have checked the checkbox, when I created the MTA and the following is in my xs-app.js file. Or am I wrong? (the mta in so post is only a snippet of the whole file for easier reading)

      The same routing-regex work in my test MTA without html5 app repo and do not work in the version with the html5 app repo. In the second case I always get an internal server error, when doing so.

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

      I've understood, that I don't need destination for my purposes. It's maybe a unlicky naming for the property destination, as you can write there a module-api, too.

      So the problems is now: How to reach my nodejs module when using html5 app repo (and no destination property for routing is available in approuter)?

       

      Best regards,

      Paige

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Paige,

      you are right, you're using the html5 app repo. I'm afraid I don't know a solution at this point, but I'll try to reach out to a colleague of mine.

      I noticed that you opened a Q&A for this one. This is great, let's move this discussion over there so that others can find it too.

       

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius Obert ,

       

      I’m working in Node Js and I need to connect odata service through Destination method.

      1. How to connect local node js app to access odata service through cloud connector.
      2. How to connect destination service in local node js app and cloud.

      Please give some idea. Thank you

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Pugazhenthi,

      good question! I assume you are referring to a local app because you would like to test the app and the service consumption before deploying it to the cloud. This is not trivial, as the Cloud Connector creates a tunnel between your on-prem system and the SAP Cloud Platform. If you want to develop on your local machine you'd need to create another "tunnel or a connect"  from the Cloud Platform back to your local dev machine.

      There are several ways how you could solve this problem:

      1. You could mock your Odata service locally
      2. You could expose your destination service via HTTP and connect to this exposed URL. WARNING: Please don't do this for productive systems!
      3. You could try to run a local version of the app router and inject the service keys of the Destination/Connectivity service instances to this app. I have never tried it, and I definitely requires advanced Cloud Foundry knowledge to do this.
      4. For simple test scenarios, I'd recommend to set up a REPL within SAP Cloud Platform as I described in this blog post. You can test how the service consumption works live in the cloud without having the need to re-deploy your code after every change.

      Hope this helped!

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius,

      Thanks for your quick replay, I will try this blog if I face any challenge let you know. Thank you.

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius Obert,

      Good Morning, Following this blog I’ve deployed node files in sap cloud foundry. And I received this-url , if I used this url in postman I got some error like this

       

      I have given my sap cloud foundry username, password in chrome its working fine but not working in postman.

      note: The OData service url is no authentication type.

      1. How to give basic authentication in destination manifest.yml file. I have given my code snap here.

      2. How to get the response data from get and post method using this destination url, I have given below my code. If I am wrong please correct me.

        Please give some idea. Thank you.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Pugazhenthi,

      seems like you do a lot of different things here (Authentication, Destinations, Node backend). I would suggest that you push the XSUAA part back and focus on the consumption of the destination.

      It'd make sense to start with a simple app as explained in this blog post and to expand the app from there.

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius,

      I have one OData service with basic authentication (On-Premise), so I need to get the data from that OData service through the Destination method in Node JS. Can you give sample code for this else documents is fine. Because I'm new in this SAP Cloud. Please give some way to do this.

      Thank you.

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author
      1. Make sure you created the destinations in the SCP cockpit properly
      2. Create the needed service instances (Destination and Connectivity)
      3. Use this simple npm module to build a node app and bind the services to it https://www.npmjs.com/package/sap-cf-destination

      I'd recommend focussing on an MVP that only consumes the service and make it run before integrating this into your project.

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius,

      I have followed this sap-cf-destination package and I deployed in sap cloud foundry but I am getting connection tunnel error.

      • On-Premise system URL also same error & Public Northwind Odata service also same error.

      Thanks in advance

      This is the error I'm getting.

      {
      "name": "RequestError",
      "message": "Error: tunneling socket could not be established, statusCode=405",
      "cause": {
      "code": "ECONNRESET"
      },
      "error": {
      "code": "ECONNRESET"
      },
      "options": {
      "url": "https://gdssap001.gdssap.net:8001/sap/opu/odata/sap/ZFIORI7_SRV/ZFIORIPRACSet",
      "resolveWithFullResponse": true,
      "simple": false,
      "proxy": "http://connectivityproxy.internal.cf.eu10.hana.ondemand.com:20003",
      "method": "GET",
      "headers": {
      "Proxy-Authorization": "Bearer eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vcDIwMDEzMDY4MDB0cmlhbC5hdXRoZW50aWNhdGlvbi5ldTEwLmhhbmEub25kZW1hbmQuY29tL3Rva2VuX2tleXMiLCJraWQiOiJrZXktaWQtMSIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjZDk2NmZiNGNmMDM0ZTM1ODRkODUyNjY0NTQwNDgxNyIsImV4dF9hdHRyIjp7ImVuaGFuY2VyIjoiWFNVQUEiLCJ6ZG4iOiJwMjAwMTMwNjgwMHRyaWFsIiwic2VydmljZWluc3RhbmNlaWQiOiI1M2I5MDRmOS03NTViLTQzNGQtYTM1Yy1kZjYwMWRkMzg3NzcifSwic3ViIjoic2ItY2xvbmU1M2I5MDRmOTc1NWI0MzRkYTM1Y2RmNjAxZGQzODc3NyFiMTQ0NDB8Y29ubmVjdGl2aXR5IWIxNyIsImF1dGhvcml0aWVzIjpbInVhYS5yZXNvdXJjZSIsImNvbm5lY3Rpdml0eSFiMTcucHJveHkiXSwic2NvcGUiOlsidWFhLnJlc291cmNlIiwiY29ubmVjdGl2aXR5IWIxNy5wcm94eSJdLCJjbGllbnRfaWQiOiJzYi1jbG9uZTUzYjkwNGY5NzU1YjQzNGRhMzVjZGY2MDFkZDM4Nzc3IWIxNDQ0MHxjb25uZWN0aXZpdHkhYjE3IiwiY2lkIjoic2ItY2xvbmU1M2I5MDRmOTc1NWI0MzRkYTM1Y2RmNjAxZGQzODc3NyFiMTQ0NDB8Y29ubmVjdGl2aXR5IWIxNyIsImF6cCI6InNiLWNsb25lNTNiOTA0Zjk3NTViNDM0ZGEzNWNkZjYwMWRkMzg3NzchYjE0NDQwfGNvbm5lY3Rpdml0eSFiMTciLCJncmFudF90eXBlIjoiY2xpZW50X2NyZWRlbnRpYWxzIiwicmV2X3NpZyI6IjQzOGZkMzZlIiwiaWF0IjoxNTU4NjgwNDMyLCJleHAiOjE1NTg3MjM2MzIsImlzcyI6Imh0dHA6Ly9wMjAwMTMwNjgwMHRyaWFsLmxvY2FsaG9zdDo4MDgwL3VhYS9vYXV0aC90b2tlbiIsInppZCI6ImZmMDkyMjhjLTY4YTEtNDg3Ni04MGI5LWIzN2E2MzM2MWZjZSIsImF1ZCI6WyJ1YWEiLCJjb25uZWN0aXZpdHkhYjE3Iiwic2ItY2xvbmU1M2I5MDRmOTc1NWI0MzRkYTM1Y2RmNjAxZGQzODc3NyFiMTQ0NDB8Y29ubmVjdGl2aXR5IWIxNyJdfQ.NZ6ihvF2gnv-jomFPN6jhyk3ACKI-JcPIZCDq-WRFYnSs7qrv5U8tOklqA1TBWS9zrKAb7FVauaOZCdqoxS7sg5kcaDcWQtEtPb6cNEN5eFnmBAdYemuQAw6t0BtLHOKBt5dyPXYuV-95DBxtlJGU-6unqlprr_O2ASmnO3-KXOhWvnlgL1w-yp8yQfSQeGf30jhFpm3CPCbNsNazRLdEczyrpz6sqsjTg_pLqVGTeLnHihXrYwQSaA1n1ZxkWgHKRcOpOvvqB-nBCALSP7K4eyzLPGndoT6qMWFmeGFT2So6hSqaBGwKrUO0HT-dqXPUmy-P8zN74nSvHA93V111EOSWPXV8IoHT2_CjNaBEFojnvPHj_ygVTS7rDvtcvBlKfB6rHvm4PWr5AEoeZR-I0pjUQ1wh9sM7srXFulFgnprpbH0rcCUleXmyi7ylSlVEZCnue4G0AsgO3ybV3Rt7WjpXdy7Fue1iLP_v_WOyZ8Xszqjp0LrkVpmz8fUpJMG9QsPlFK1af5X6XMgkciFBKMIzCXLItPVF-mrAfBIQRsHxqxeNZwr83UHRWWfNu00HvEpn4Cb9tHEEN1f-WEoivoDHcVg2uS85Qhcsj8rKYt0t_tDalXRWN-OSBH5A3AzCh8qm9yDSMRKdoCUFZESMBzcbPUT3aDU-_H7qYEup7o",
      "Authorization": "Basic dmVtdWxhZDpFbHVydUAxNDM=",
      "Content-type": "application/json"
      },
      "transform2xxOnly": false
      }
      }




      {
      "name": "RequestError",
      "message": "Error: tunneling socket could not be established, statusCode=405",
      "cause": {
      "code": "ECONNRESET"
      },
      "error": {
      "code": "ECONNRESET"
      },
      "options": {
      "url": "https://services.odata.org/V3/Northwind/Northwind.svc",
      "resolveWithFullResponse": true,
      "simple": false,
      "proxy": "http://connectivityproxy.internal.cf.eu10.hana.ondemand.com:20003",
      "method": "GET",
      "headers": {
      "Proxy-Authorization": "Bearer eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vcDIwMDEzMDY4MDB0cmlhbC5hdXRoZW50aWNhdGlvbi5ldTEwLmhhbmEub25kZW1hbmQuY29tL3Rva2VuX2tleXMiLCJraWQiOiJrZXktaWQtMSIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiMGRjNmU4OGEyNmY0NDFjODMwYmZhNTRkMjY1MTdjNSIsImV4dF9hdHRyIjp7ImVuaGFuY2VyIjoiWFNVQUEiLCJ6ZG4iOiJwMjAwMTMwNjgwMHRyaWFsIiwic2VydmljZWluc3RhbmNlaWQiOiI1M2I5MDRmOS03NTViLTQzNGQtYTM1Yy1kZjYwMWRkMzg3NzcifSwic3ViIjoic2ItY2xvbmU1M2I5MDRmOTc1NWI0MzRkYTM1Y2RmNjAxZGQzODc3NyFiMTQ0NDB8Y29ubmVjdGl2aXR5IWIxNyIsImF1dGhvcml0aWVzIjpbInVhYS5yZXNvdXJjZSIsImNvbm5lY3Rpdml0eSFiMTcucHJveHkiXSwic2NvcGUiOlsidWFhLnJlc291cmNlIiwiY29ubmVjdGl2aXR5IWIxNy5wcm94eSJdLCJjbGllbnRfaWQiOiJzYi1jbG9uZTUzYjkwNGY5NzU1YjQzNGRhMzVjZGY2MDFkZDM4Nzc3IWIxNDQ0MHxjb25uZWN0aXZpdHkhYjE3IiwiY2lkIjoic2ItY2xvbmU1M2I5MDRmOTc1NWI0MzRkYTM1Y2RmNjAxZGQzODc3NyFiMTQ0NDB8Y29ubmVjdGl2aXR5IWIxNyIsImF6cCI6InNiLWNsb25lNTNiOTA0Zjk3NTViNDM0ZGEzNWNkZjYwMWRkMzg3NzchYjE0NDQwfGNvbm5lY3Rpdml0eSFiMTciLCJncmFudF90eXBlIjoiY2xpZW50X2NyZWRlbnRpYWxzIiwicmV2X3NpZyI6IjQzOGZkMzZlIiwiaWF0IjoxNTU4NjgyMTUwLCJleHAiOjE1NTg3MjUzNTAsImlzcyI6Imh0dHA6Ly9wMjAwMTMwNjgwMHRyaWFsLmxvY2FsaG9zdDo4MDgwL3VhYS9vYXV0aC90b2tlbiIsInppZCI6ImZmMDkyMjhjLTY4YTEtNDg3Ni04MGI5LWIzN2E2MzM2MWZjZSIsImF1ZCI6WyJ1YWEiLCJjb25uZWN0aXZpdHkhYjE3Iiwic2ItY2xvbmU1M2I5MDRmOTc1NWI0MzRkYTM1Y2RmNjAxZGQzODc3NyFiMTQ0NDB8Y29ubmVjdGl2aXR5IWIxNyJdfQ.Q9Gt166PkcMlWpaRmHSTSn-pHmLbJ2k9jtUGOGYOAywUIJtpBaSZv_yQjaAZGYQpeKonKfxzN7WKo_H9oBlYsIuW4lqbb0MsbicHhOUgWmZz8248RlembTuqsv8nQditescenda7qiU-foM7lVTUWpZlaScFLO0jSAZmB2pYXfUtDXklgHlCv2KZrdlc889Ne2P-9HBQxYLdfln-4fKc62sx6UF2bpZZxL4ICMVOfMhC8jmmiydxVamuqMQNZzKYHH1A9dmajqUqoWB24hMNhxcL4qvakYNLROnBkXkuzt6zmhRkW00rKPHxpQ1KQI4Vfxr7NCxAsHZpoOfIR4x5NhRWu6XEBeXTFF99F9NX40sO0xYZuv5v9rY-9o7373A8--mhnWESpaAeCp2yvRPXwEG8vZBWDOyXtHhQGA_rniAqU9DjPoKP0enFXTi2UbSIRBQljiqGKUWc2TXoLPfBASK_TeGKYkBv_pBbiunvvz-21l9asikELxeK0Wp3IqNpCLJIt4aS4bX-8YijRZEWsEBZal1bwBp2BO-s9MIL9LsEftU2TTpXZ33SnmZSOpCw4XDOPZIWqKam-h2E67gVBGiG8GSu8HiCy8KSwnl-yQE2ewMGxi7rhhjsmZHqoqzAI9KalZQ5uX14QQkfIhLV5Vyy_gXqU84I7otXnqniJKw",
      "Content-type": "application/json"
      },
      "transform2xxOnly": false
      }
      }
      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Looks like there has been an issue with the connectivity service and the Cloud Connector setup. The Cloud Foundry app itself seems to work fine.

       

      I'm afraid I cannot help you with this one. Please search for this issue in the Community or ask a new question there.

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Sure I will ask to them. Thank you.

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius,

      Good afternoon,

      Is there any other way to connect OData service through destination method in node js.

      I have tried that sap-cf-destination what you sent getting same error mentioned above.

      Please give some other document to do that or any workable github code.

      It will great helpful for me. Thank you.

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I think the problem you're facing isn't related to the nodejs code. Most likely, it's the setup of the Cloud Connector and/or the backend system.

      Author's profile photo Pugazhenthi K
      Pugazhenthi K

      Hi Marius,

      I got the answer really thanks for your great support.

      Cloud connector between the backend system is the problem.

      Thank you.

       

       

      Author's profile photo Stefanie Heil
      Stefanie Heil

      Hi Pugazhenthi,

      can you give me a hint of the solution. We got the same error.

      What was wrong with the Cloud connector?

       

      Author's profile photo Former Member
      Former Member

      Stefanie Heil Pugazhenthi K Could you please elaborate the answer.I am getting the same error.

      Author's profile photo DurgaPrasanth vemula
      DurgaPrasanth vemula

      Hi,

      Using .Net we had to consume Cloud Foundry destination and it is possible and if it is yes could you please share the sample code

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Durga,

      I'm afraid I'm not a .net expert at all (I've never used it, to be honest). I don't think I can provide you with a sample here, but it should work analogous to the examples above.

      Maybe this GitHub project can help you to get started.

      Author's profile photo Javier Rodriguez Prieto
      Javier Rodriguez Prieto

      Hi Marius,

      I read this blog to contact with the destination and is so useful. But unfortunately, i'm getting a bad response when i use "sap-cf-destination" in nodejs:

      const callDestination = require('sap-cf-destination');
      callDestination({
              url: '/sap/opu/odata/ZSERV/ZSENT_SRV/UpdateSent',
              connectivity_instance: 'connectivity_service',
              uaa_instance: 'uaa_service',
              destination_instance: 'destination_service',
              destination_name: 'SAP_ECC_800',
              http_verb: 'POST',
              payload: {
              }
              .then(response => {
                  console.log(response);
                  console.log("was fine");
             })
              .catch(err => {
                  console.log(err);
                  console.log("Error");
              })
      }
      

      But I'm getting the following response:

      <html><head><title>Logon Error Message</title><META http-equiv="Content-Type" content="text/html;charset=UTF-8"><style type="text/css">body { font-family:tahoma,helvetica,sans-serif;color:#333333;background-color:#FFFFFF; }td { font-family:tahoma,helvetica,sans-serif;font-size:70%;color:#333333; }h1 { font-family:tahoma,helvetica,sans-serif;font-size:160%;font-weight:bold;margin-top:15px;margin-bottom:3px;color:#003366; }h2 { font-family:verdana,helvetica,sans-serif;font-size:120%;font-style:italic;font-weight:bold;margin-top:6px;margin-bottom:6px;color:#999900; }p { font-family:tahoma,helvetica,sans-serif;color:#333333;margin-top:4px;margin-bottom:4px; }ul { font-family:tahoma,helvetica,sans-serif;color:#333333;list-style-type:square;margin-top:8px;margin-bottom:8px; }li { font-family:tahoma,helvetica,sans-serif;color:#33333;margin-top:4px; }.emphasize { color:#333333;background-color:#C8E3FF;padding:5px;}.note { color:#CC6600; }a { font-family:tahoma,helvetica,sans-serif;text-decoration:underline;color:#336699; }a:visited { color:#001166; }a:hover { text-decoration:none; }</style></head><body><table cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td><h1>Anmeldung fehlgeschlagen</h1></td></tr></table></body></html>

      Http code 401 with the body "Anmeldung fehlgeschlagen"

      So my suspicions is, the error is in "Cloud connector", however this destination is possible to consume directly from my app router without any issues. Appreciate any help to identify where is the issue.

      Thanks

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Javier,

      you are right, this seems to be an issue with the Cloud Connector and I'm afraid I don't know how to fix this (Unfortunately, I'm not a CC expert).

       

      Sorry

      Author's profile photo Javier Rodriguez Prieto
      Javier Rodriguez Prieto

      Hi Marius,

      Finally we had two issues, one is because the cloud connector set up with a wrong configuration and the other was for wrong client access. So I'm not an CC expert as well 🙂

      I'd like to suggest a one little change in the tool in nodejs "sap-cf-destination" (i think you were involved in this). I cannot see in this tool the parameter x-csrf-token in the header, and this is required to contact with odata. Do you think is possible to add it? or maybe is my mistake and i didn't see it 🙂

      Thanks

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Javier,

       

      great to hear that you were able to fix it :)!

      I wasn't involved in the "sap-cf-destination" tool, but I know Volker Buzek who started the repo/package. I'm sure he'd be happy to get feedback from you.

      I'd suggest opening a new GitHub issue for this.

      Author's profile photo Volker Buzek
      Volker Buzek

      Hi Javier Rodriguez Prieto and Marius Obert,

      I just peaked at the source and you're correct, the x-csrf-token header is not in there.

      Please leave a feature request as Marius suggested in the repo, then I can get to work once I have a little spare time on my hands.

      Or even better: you add the header option and due a pull request!!! 🙂

      Best, V.

      Author's profile photo Javier Rodriguez Prieto
      Javier Rodriguez Prieto

      Many Thanks Volker and Marius,

      I’ll try to create a pull request when i have time.

      Beautiful job with this library, make our life easier.

      Author's profile photo diego martin oliver
      diego martin oliver

      Hi Javier Rodriguez Prieto , Volker Buzek ,

       

      Was that pull request created finally to be able to add in the header that "x-csrf-token"?

      I don't see that feature it in the repository so I'm calling a SAP Gateway OnPremise service and gives me the error of validation of CSRF Token 🙁 ...

      Thanks in advance

      Diego

       

      Author's profile photo Volker Buzek
      Volker Buzek

      unfortunately Javier Rodriguez Prieto hasn't found the time (yet?) to do the bespoken PR/change. Probably you wanna take over? 😉

      Author's profile photo Javier Rodriguez Prieto
      Javier Rodriguez Prieto

      Hi Volker,

      My apologies, i was so busy and i couldn't change. This is the consultancy life 🙂

      In addition, I think we need to update more things... because packages "request-promise" and "request" are deprecated.

      Now, I'm working in migrate all to "node-fetch" library.

      Author's profile photo Volker Buzek
      Volker Buzek

      hi, no sweat, that's how it is 🙂

      might also look into "axios" or "got" as alternative to node-fetch.

      looking fwd to the PR, v.

      Author's profile photo Sebastiano Marchesini
      Sebastiano Marchesini

      Hi Marius,
      thank you for blog.

       

      Two question:

      Is it possible that in my trial account (without any organization created before), there isn't the Destination service ?

       

      Could I, with my Trial account and with cockpit.hanatrial.ondemand, connect and create a python application in cloud foundry ?

      Thank you,

      regards
      Sebastiano

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Sebastiano,

      It seems that the "destination" service is not activated in your trial account. Please configure the entitlements of your account and add the service plan "destination". Then, it should work.

       

      Regards,

      Marius

      Author's profile photo Rajesh Ranjan
      Rajesh Ranjan

      Hi Marius,

      Can u please share a working code example for consuming sap cloud destination from SAP UI5 mta App.Thanks in advance.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Rajesh,

       

      sure, this sample app here is, for example, consuming a destination. As you can see in the xs-app.json, it actually consumes two destinations via two routes.

      Author's profile photo Saurabh Parikh
      Saurabh Parikh

      Hi Marius,,

      Thanks for the blog. It is really informative.

      When I am using the destination service and create UI5 project using webide, the application works fine and I am able to get the data.

      I have a requirement to use XSUAA service for authentication and I have developed the app using node.js and added UI5 path using routes in my start.js file. UI5 app is running directly on the browser.

      Manifest.yml

      applications:
      – name: sapui5
        host: sapui5
        command: node start.js
        path: sapui5
        memory: 512M
        buildpack: nodejs_buildpack
        services:
          – myuaa
          – mydestination
      – name: sapweb
        host: sapweb
        path: sapweb
        buildpack: nodejs_buildpack
        memory: 256M
        env:
          destinations: >
            [
              {
                “name”:”sapui5″,
                “url”:”https://sapui5.cfapps.eu10.hana.ondemand.com”,
                “forwardAuthToken”: true
              }
            ]
        services:
          – myuaa
          – mydestination

      Now when I am using destination service and calling from UI5 app, it is giving me 500 – Internal Server Error. Somehow I feel that it is not connecting to destination service. I am using manifest.yml and added destination as above.

      xs-app.json

      {
        “authenticationMethod”: “route”,
        “routes”: [
          {
            “source”: “^/sapui5/(.*)$”,
            “target”: “$1”,
            “destination”: “sapui5”
          },
          {
            “source”: “^/northwind/(.*)$”,
            “target”: “$1”,
            “destination”: “northwind”
          }
        ]
      }

       

      I have to call destination service from UI5 app. Could please help me to find the issue?

      Thanks.

       

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Saurabh,

      I'm not sure if I understand the architecture from reading the manifest file.

      Is it possible that both apps (sapui5 and sapweb) are app routers? In this case, I would recommend getting rid of one approuter. This will simplify the overall design and remove pitfalls. I think it makes sense to follow this tutorial as it seems to cover a similar scenario.

      In general: If you received a "500 error", you can use the CF CLI "cf logs <sapweb/sapui5>" to see detailed error messages.

       

      Author's profile photo Saurabh Parikh
      Saurabh Parikh

      Hi Marius,

      "sapui5" is HTML5 app and "sacweb" is my app router.

      Anyways, I will go through that tutorial.

      Thanks:)

      Author's profile photo Alagar Pandian
      Alagar Pandian

      Hi Marius,

      I wanted to use Fiori launchpad portal from cloud foundry hence i had to check html5 repository option while creating MTA project. Now that i have created two ui5 apps inside my MTA project. I have created a destination in cloud foundry aswell.

      Can you kindly guide me how can I consume the destination in my UI5 apps  as I read somewhere that destination property is not supported if HTML5 repo is enabled.

      I just updated the xs-app.json as you mentioned in this post but getting 404 not found error while testing from NEO.

       

       

      Thanks in Advance

       

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Alagar,

      I'm glad you're using the HTML5 app repo 🙂 Destination properties are supported when using the HTML5 repo, so this isn't the problem.

      It is important to note that you have n+1 xs-app.json files when you deploy n web apps to the repo. You have one xs-app.json for the approuter (which declares all routes/destinations on the root of the URL of the approuter) and one per HTML5 app (which declares all routes/destinations per web app.

      https://612xxxxxx-approuter.cfapps.eu10.hana.ondemand.com/rootDestination1/ # This destination needs to be defined in the xs-app.json of the approuter
      
      https://612xxxxxx-approuter.cfapps.eu10.hana.ondemand.com/comDemoWebApp1/nestedDestination1/ # This destination needs to be defined in the xs-app.json of the first web app comDemoWebApp1
      
      https://612xxxxxx-approuter.cfapps.eu10.hana.ondemand.com/comDemoWebApp2/nestedDestination2/ # This destination needs to be defined in the xs-app.json of the second web app comDemoWebApp2

      From your screenshot, I would assume that you need to add the destination to the xs-app.json of your web app.

      Author's profile photo Alagar Pandian
      Alagar Pandian

      Thanks a lot for your response.

      Now that my individual html5 apps are working in my MTA project but  after deployment when i open those apps from fiori launchpad tile, giving 500 internal server  error for component.js file loading.

      I don't have any xs-app.json file for approuter. I think that is the reason. Can you please share a sample format or document for the same. I am confused with what is root destination and nested destination now as I only have one destination created in CF.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      It is strange that you get a 500 error for the component.js. This could either mean that the component.js is missing from the HTML5 app repo (unlikely) or that the URL to the component.js is hardcoded/absolute in the index.html and points to an incorrect URL. I think the second option is more likely.

       

      About the approuter, it is not possible to deploy an approuter without a xsapp.json, so I assume you have one in place

      Author's profile photo Tapishnu Sengupta
      Tapishnu Sengupta

      Hi Marius,

       

      I want to read all destinations available in my subaccount and show the details in a ui5 application in CF. Is this possible?

       

      Regards,

      Tapishnu

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi,

       

      it is possible from the backend when you communicate directly with the destination service. In this case, you need a backend proxy that fetches the data and returns it to the frontend.

      https://api.sap.com/api/SAP_CP_CF_Connectivity_Destination/resource

      Author's profile photo Rajdeep BHUVA
      Rajdeep BHUVA

      Hi Marius,

       

      Very Informative Blog post!

       

      I want to use destination service in my local project which has node.js module and SAPUI5 module. I Created service key in destination service and using it i created user provided service with tag destination. It is working fine for Node modules but, for sapui5 module it is using approuter and somehow approuter is not fetching the details from user provided service.

       

      Do you know anything we could do here which can help approuter to use destination service using user provided service.

       

      Thanks,

      Rajdeep Bhuva

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Rajdeep,

      is the destination also defined in the xs-app.json configuration of the approuter? You might be able to find some hints in the log of the approuter when you call the route (that points to the destination).

       

      You could also check if the coding itself is alright you deploy the application to CF and bind it to the destination service instance.

      Author's profile photo Rajdeep BHUVA
      Rajdeep BHUVA

      Hi Marius,

      I am running application outside SAP CF so destination service is not available. I was trying to use credentials of destination service of SAP CF for my local project.

      Finally i achieved it by settings VCAP_SERVICES variable before starting approuter.

      Thanks,

      Rajdeep Bhuva

      Author's profile photo Sumit Kumar Kundu
      Sumit Kumar Kundu

      Nicely explained. I have a question. When should we choose SAP Cloud Platform Connectivity destination vs. destination service instance?

      Best regards,

      Sumit

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Can you add more details about the services you are referring to? I don't think there are two different types of services.

      Author's profile photo Sumit Kumar Kundu
      Sumit Kumar Kundu

      Please see the screenshot below (1 vs. 2)..

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Both are the same service. In the main screen (1), you can create new service instances that can later be bound to a CF app. Each service instance contains its own destinations which are only accessible by bound applications.

      The side panel (2) allows you to configure destinations on the subaccount level. These destinations have a larger scope and are available to apps that are bound to ANY service instance.

      Author's profile photo Sumit Kumar Kundu
      Sumit Kumar Kundu

      Thanks for explanation. So the only difference is the 'scope' as far as the bound apps are concerned.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Yes, both user interfaces belong to the same service. The scope of the destination will vary depending on the UI you used to enter it.

      Author's profile photo Shanir Tvaija
      Shanir Tvaija

      Hi Marius Obert

      I need advice in applying this technique in webIDE to open external url in new window with few url parameters and one of the parameters is redirect url.

      Any tips on how to achieve the opening of new window without using hardcoded url, that would also take into account additional url parameters?

       

      Thank you!!

      Shan

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      You can use the destination service to avoid hard-coded URLs in your app, yes.

      I'm not sure if I understand the other parts of your question. The Web IDE is a development environment and cannot open URLs in new tabs.

      Can you please explain what kind of an app you're building?

      Author's profile photo Shanir Tvaija
      Shanir Tvaija

      Haha, sorry for not being clear, my english maybe not so good.

      I have an UI5 app, developed as MTA with HTML5 Modules. and in this app I need to open new window, with command (window.open or iframe), but the url for this needs to contain several url parameters.

      So my question how and where the parameters can be indicated? in CF Destination definition or in webIDE while calling the destination.

       

      Thanks!

      Shanir

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I think I got it now 🙂

      In either case, I'd use the following JS snippet to open a new window.

      window.open(myURL)

      I would say it depends on how often the links change. If that only happens every few months, I'd probably hard-code it and update the entire web app if the link changes.
      If you want to be more agile, I recommend that a backend service send this URL to your UI5 app. This backend component can then read the URL from the destination service (or a database). UI apps (independent of the framework) cannot directly consume the destination service - only via an approuter (which is a backend component).

      Author's profile photo Shanir Tvaija
      Shanir Tvaija

      Ok, let me see if I understand this.

      If we have MTA app built in webIDE with UI5 Module that utilizes ABAP in Cloud as a backend oData service - there is no way in webIDE to directly consume Destination from CF that holds the url?

      When deploying the MTA I can see in CF Space that for the application the approuter is running and has service binding to abap in cloud.

      So the way in this case to avoid no-hardcoded-url would be what?

       

      Thanks a lot!

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I wouldn't mention the Web IDE (or any other IDE) in this context. This is only a tool for building web app but the tool itself should not and does not consume data from any destination.

       

      Author's profile photo Shanir Tvaija
      Shanir Tvaija

      Yes, sure! I don't understand why are you saying things about webIDE being a tool that doesn't consume destination itself? This is not at all my question, I was asking to how to code a line in webIDE for the app to connect to CF destination with url params.
      let me ilustrate it, maybe better:

      coding%20in%20webIDE

      coding in webIDE

      so in this case I am asking hot to configure CF destination and coding in webIDE - to not write hardcoded url, but utilize the destination.

       

      Hope it is now better understandable.

      Thanks!

      Author's profile photo Tim Cashmore
      Tim Cashmore

      Hi Marius

      Hopefully a quick question around the best way to connect an SAPUI5 app (standalone approuter deployed in cf) to a node.js "microservice" I have created which has its own approuter.  I have bound both applications to the same xsuaa service instance.  I wanted to keep the front-end separate from the backend node.js application.

      The node.js app is using the standard SAP middleware to authenticate user access - works fine if I enter the URL into the browser (will redirect to logon and then check scopes) and then respond with JSON content.

      However, I am struggling to work out the best way to connect my SAPUI5 app to this API I have created.  I have tried a destination (both as an environment variable in mta.yaml and a destination set-up in the SCP cockpit but it doesn't seem to work - keep getting a 401 and the API approuter doesn't forward on the request.  I am not sure if this the best method to build a deploy the API and then connect to it from the front-end app.

      Hopefully this makes sense !

      Many thanks

      Tim

       

       

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Tim,

      that sounds like you don't use the right authentication type of the destination. You need to choose one to exchange the auth token of approuter 1 to approuter 2. I'm not an expert here so I can't give you more specific instructions, sorry.

      In general, I would recommend that one approuter should be enough. CAP apps also provide their server functionality without an approuter and you only need it when the app is combined with a frontend and human user interaction. I understand that there could be some special reasons to have multiple app routers - I just wanted to say it's not the most straight forward option.

      Author's profile photo Tim Cashmore
      Tim Cashmore

      Hi Marius

      Thanks for the update - it makes sense now that I don't need 2 approuters - it seems to go into a loop of requesting authentication between the 2 approuters.   I've just amended the destination definition in mta.yml to point directly to the application 'microservice' URI (rather than the approuter) and connects fine and returns the JSON.  Just need to check that the scopes work ok now!

      Many thanks

       

      Author's profile photo Ramon Lee
      Ramon Lee

      Hi Marius,

      The screen below is taken during debugging mode. I have mapped the destination instances to my local build via .env file. When trying to consume GW services via destination through cloud connector, i receive an TCP IP error message, how do i work around this?

      I have tested the same on cloud foundry, and the same is unable to call the GW services from my nodejs app. Can you advise further on this.

      CF%20Destination%20%28backend%29

      CF Destination (backend)

       

      Ramon

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Ramon,

      I'm not sure what the issue is here and it is not directly related to the generic content of the post. There could be multiple reasons why it doesn't work.
      You could try to use this destination in an approuter to make sure it's working in the first place (before trying to use it in your project).

       

      Regards,

      Marius

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I just added a video that explains how to make sure your destination is working. Maybe it helps you.

      Author's profile photo Alfredo Semeco Blanco
      Alfredo Semeco Blanco

      hi Marius Obert

       

      Thanks for this blog!.

       

      Marius in this moment I am trying to consume a destination from my SAPUI5 app , but when I test the service consume, i am gettin a 404 not found message like service repsonse.

       

      this is my xs-app.json config:

      {

        "welcomeFile": "/index.html",
        "authenticationMethod": "route",
        "logout": {
          "logoutEndpoint": "/do/logout"
        },
        "routes": [
          {
            "source": "^(.*)$",
            "target": "$1",
            "service": "html5-apps-repo-rt",
            "authenticationType": "xsuaa"
          },{
            "source": "^/confiar/(.*)$",
            "target": "/$1",
            "destination": "confiar"
      }
        ]
      }

       

      My bind services resources mta.yaml:

       

      resources:
      - name: destination
        parameters:
          service-plan: lite
          service-name: AppTestWeb_destination
          service: destination
        type: org.cloudfoundry.managed-service
      - name: AppTestWeb_html_repo_runtime
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-plan: app-runtime
      - name: AppTestWeb_html_repo_host
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-plan: app-host
      - name: uaa_AppTestWeb
        type: org.cloudfoundry.managed-service
        parameters:
          path: ./xs-security.json
          service: xsuaa
          service-name: AppTestWeb-xsuaa-service
          service-plan: application
      and my client http to test the destination:
      $http({
                  method: 'GET',
                  url: "/confiar",
              }).success(function (response, status, headers, config) {
                  alert("esponse"+ response);
                  alert(status);
              }).error(function (response, status, headers, config) {
                   alert("Err "+response + status);
              });
      My destination is config with name: confiar. portocol: HTTP , Proxy: Internet . is a simple REST Srvice.
      Can you help me?, i dont know why i'm getting a 404 not found. If yo need my code appreciate your great help.
      Thanks again

       

       

       

       

       

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Alfredo,

       

      the first thing that I noticed when I look at your xs-app.json is that the order of the routes seems off. The first route matches everything and basically "catches" all traffic which means no traffic is sent to the second route. Try to reverse them and maybe it works then.

      Author's profile photo Alfredo Semeco Blanco
      Alfredo Semeco Blanco

      Hi Marius Obert

       

      I tried it but still getting the same 404 not found...

       

      The test:

      {
          "welcomeFile": "/index.html",
          "authenticationMethod": "route",
          "logout": {
              "logoutEndpoint": "/do/logout"
          },
          "routes": [
              {
                  "source": "^/confiar/(.*)$",
                  "target": "/$1",
                  "destination": "confiar"
              },
               {
                  "source": "^(.*)$",
                  "target": "$1",
                  "service": "html5-apps-repo-rt",
                  "authenticationType": "xsuaa"
              }
          ]
      }
      Other thing  that you can see
      Thanks
      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Which URL do you request? Please be aware that you need to match the regex fully.

      A request to "/confiar" won't match because it's missing the closing / and something "behind it".

      Author's profile photo Alfredo Semeco Blanco
      Alfredo Semeco Blanco

      Hi Marius Obert

      case from CF (app deployed):

      the URL is  : The URL Path is: "https://xxxxxcfecctrial-dev-apptestweb-approuter.cfapps.eu10.hana.ondemand.com/nsHTML5Module/index.html"

      When i deploy in CF the app and run it get 404 not found in the destination's request.

       

      Marius Obert i show you another interest data:

       

      My destination has the attributes:

      destination%20attribute

      destination attribute

      package.json

      {
        "name": "apptestweb",
        "version": "0.0.1",
        "devDependencies": {
          "@sap/ui5-builder-webide-extension": "1.0.x",
          "@ui5/cli": "2.2.6",
          "eslint": "5.16.x",
          "@sap/eslint-plugin-ui5-jsdocs": "2.0.x",
          "@sapui5/ts-types": "1.71.x",
          "bestzip": "2.1.4",
          "rimraf": "3.0.2",
          "@sap/approuter": "9.3.0",
          "@sap/html5-repo-mock": "2.0.0"
        },
        "ui5": {
          "dependencies": [
            "@sap/ui5-builder-webide-extension"
          ]
        }
      }
      mta.yaml
          commands:
          - npm run build
          supported-platforms: []
      resources:
      - name: destination
        parameters:
          service-plan: lite
          service-name: AppTestWeb_destination
          service: destination
        type: org.cloudfoundry.managed-service
      - name: AppTestWeb_html_repo_runtime
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-plan: app-runtime
      - name: AppTestWeb_html_repo_host
        type: org.cloudfoundry.managed-service
        parameters:
          service: html5-apps-repo
          service-plan: app-host
      - name: uaa_AppTestWeb
        type: org.cloudfoundry.managed-service
        parameters:
          path: ./xs-security.json
          service: xsuaa
          service-name: AppTestWeb-xsuaa-service
          service-plan: application
      build-parameters:
        before-all:
        - builder: custom
          commands:
          - npm install
      ui5.yaml
      specVersion: '1.0'
      metadata:
        name: HTML5Module
      type: application
      resources:
        configuration:
          propertiesFileSourceEncoding: UTF-8
      builder:
        resources:
          excludes:
            - "/test/**"
            - "/localService/**"
        customTasks:
        - name: webide-extension-task-updateManifestJson
          afterTask: generateVersionInfo
          configuration:
            appFolder: webapp
            destDir: dist
        - name: webide-extension-task-resources
          afterTask: webide-extension-task-updateManifestJson
          configuration:
            nameSpace: ns
        - name: webide-extension-task-copyFile
          afterTask: webide-extension-task-resources
          configuration:
            srcFile: "/xs-app.json"
            destFile: "/xs-app.json"
      manifest.json
      {
          "_version": "1.12.0",
          "sap.app": {
              "id": "ns.HTML5Module",
              "type": "application",
              "i18n": "i18n/i18n.properties",
              "applicationVersion": {
                  "version": "1.0.0"
              },
              "title": "{{appTitle}}",
              "description": "{{appDescription}}",
              "resources": "resources.json",
              "ach": "ach",
              "sourceTemplate": {
                  "id": "html5moduletemplates.basicSAPUI5ApplicationProjectModule",
                  "version": "1.40.12"
              },
              "crossNavigation": {
                  "inbounds": {
                      "intent1": {
                          "signature": {
                              "parameters": {},
                              "additionalParameters": "allowed"
                          },
                          "semanticObject": "Dynamic",
                          "action": "display",
                          "title": "{{appTitle}}",
                          "info": "{{appTitle}}",
                          "subTitle": "{{appSubTitle}}",
                          "icon": "sap-icon://sales-order"
                      }
                  }
              }
          },"sap.cloud": {
              "service": "com.sap.jalf.app"
          },
          "sap.ui": {
              "technology": "UI5",
              "icons": {
                  "icon": "",
                  "favIcon": "",
                  "phone": "",
                  "phone@2": "",
                  "tablet": "",
                  "tablet@2": ""
              },
              "deviceTypes": {
                  "desktop": true,
                  "tablet": true,
                  "phone": true
              }
          },
          "sap.ui5": {
              "flexEnabled": false,
              "rootView": {
                  "viewName": "ns.HTML5Module.view.TestView",
                  "type": "XML",
                  "async": true,
                  "id": "TestView"
              },
              "dependencies": {
                  "minUI5Version": "1.60.1",
                  "libs": {
                      "sap.ui.core": {},
                      "sap.m": {},
                      "sap.ui.layout": {}
                  }
              },
              "contentDensities": {
                  "compact": true,
                  "cozy": true
              },
              "models": {
                  "i18n": {
                      "type": "sap.ui.model.resource.ResourceModel",
                      "settings": {
                          "bundleName": "ns.HTML5Module.i18n.i18n"
                      }
                  }
              },
              "resources": {
                  "css": [
                      {
                          "uri": "css/style.css"
                      }
                  ]
              },
              "routing": {
                  "config": {
                      "routerClass": "sap.m.routing.Router",
                      "viewType": "XML",
                      "async": true,
                      "viewPath": "ns.HTML5Module.view",
                      "controlAggregation": "pages",
                      "controlId": "app",
                      "clearControlAggregation": false
                  },
                  "routes": [
                      {
                          "name": "RouteTestView",
                          "pattern": "RouteTestView",
                          "target": [
                              "TargetTestView"
                          ]
                      }
                  ],
                  "targets": {
                      "TargetTestView": {
                          "viewType": "XML",
                          "transition": "slide",
                          "clearControlAggregation": false,
                          "viewId": "TestView",
                          "viewName": "TestView"
                      }
                  }
              }
          }
      }
      Thanks for you help. 
        
      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I meant which URL is expected to return the data from the destination. If you set everything up correctly, it should be similar to:

      https://xxxxxcfecctrial-dev-apptestweb-approuter.cfapps.eu10.hana.ondemand.com/confiar/.....

      If that doesn't work, it could mean that your destination is not working as expected. Here's a brand-new video tutorial that explains how you can test it.

      Author's profile photo Alfredo Semeco Blanco
      Alfredo Semeco Blanco

      Yes, my endpoint is like that:

      https://xxxxxcfecctrial-dev-apptestweb-approuter.cfapps.eu10.hana.ondemand.com/confiar/...

       

      I am testing the destination and i am getting the next result:

      DestinationTestCurl

      DestinationTestCurl

       

      My destination endpoint (origin endpoint)is not passing by SAP Cloud Connector, is not a problem, really? or it is necessary to do it,  i need to pass my endpoint (Is a internet endpoint) exposing in my SCC? i guess for this case is not necessary but i don't really know...

      CheckConnectionDestination TestConnectionDestinationCF

      TestConnectionDestinationCF

       

      The connection it's OK . Endpoint Basic Auth it's Ok too!.

       

      What could be?. My endpoint is a API REST App Java deployed in SAP NEO.  Simple internet endpoint...

      Thanks for the video! and

      Thanks for your help

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Try it without the "WebIDEUsage" and the "HTML5Preset" properties. Use just these two:

      Author's profile photo Alfredo Semeco Blanco
      Alfredo Semeco Blanco

      Thanks so much, you are the best man!

       

      I already got an answer, it is only necessary to place those two properties!!

       

      Again, thanks so much for your help and appreciate your time a lot!

       

      Author's profile photo Alfredo Semeco Blanco
      Alfredo Semeco Blanco

      Hi Again  Marius Obert

      I got a result OK making the Curl test destination. It's OK.

      I made a test running my app html5 from BAS IDE and the result is OK Too, The destination is consumed from the app without problem.  Response OK

      My app running from BAS and service xsuaa and destination (bindign from BAS)

      AppRunningFromBassIDE

      AppRunningFromBassIDE

       

      Now i am deploying my app html5 to CF with own service instance (created from mta.yaml). When  the app is deployed, is making binding with the services:

      ServicesIntanceCFapp

      ServicesIntanceCFapp

      Finally when i run my app, the app get response 404 NOT FOUND when the destinations is consume...

       

      why the app works in BAS  but when I deply show this 404 not found. ? I need to do smothing more? 

       

      ***UPDATE**: 11/03/2021

      Marius Obert  I got the solution!. 

       

       

      Author's profile photo Jeremy CHABERT
      Jeremy CHABERT

      Hello Marius Obert ,

      I have open a question that might be related to this.

      Could you have a look ?

      https://answers.sap.com/questions/13318318/request-proxied-differently-thought-called-from-th.html

      Author's profile photo Wolfgang Röckelein
      Wolfgang Röckelein

      Hi Alfredo Semeco Blanco ,

      ***UPDATE**: 11/03/2021

      Marius Obert  I got the solution!. 

      And what is the solution exactly?

      Thanks,

        Wolfgang

      Author's profile photo Wolfgang Röckelein
      Wolfgang Röckelein

      Hi Marius Obert ,

      Try it without the "WebIDEUsage" and the "HTML5Preset" properties.

      so WebIDEUsage is not needed for BAS?

      Regards,

      Wolfgang

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I can't give you an official answer here but I don't think it's needed. At least not in any of the scenarios that I use regularly 🙂

      Author's profile photo Wolfgang Röckelein
      Wolfgang Röckelein

      Hi Marius Obert ,

      thank you very much for the fast answer!

      Of course another question would be if this entry would be harmful...

      IMHO we need a definitive list of properties necessary for BAS.

      Regards,

      Wolfgang

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I agree - a definitive guide would be nice but hard to implement as each service can add their own additional props as needed.

      For the SAP Business Application Studio, I found an official answer in the documentation 🙂

      Here, they also mention that just WebIDEEnabled is required (I guess you problem is just caused by WebIDEUsage as it assumes you connect to ABAP ABAP system).

       

      And there's another document describing the additional props related to HTML5 apps.

      Author's profile photo Wolfgang Röckelein
      Wolfgang Röckelein

      Hi Marius Obert ,

      yes, I agree a single guide would be too hard. But a least a guide per use case (and not only per tool) would be nice.

      Based on the docu and the screenshot I would guess Alfredo did not have "HTML5Preset" but "HTML5.PreserveHostHeader".

      So both "WebIDEUsage" and "HTML5.PreserveHostHeader" are among those are strictly and optionally needed for a BAS-based deployment of HTML5 app to CF and therefore should definitly not give any problems.

      Regards,

      Wolfgang

      Author's profile photo Johan Gaitán
      Johan Gaitán

      Hi Marius Obert,

      I'm treating to Migrate an application from NEO environment to Cloud Foundry environment and I want to consume a destinations I followed the stepts you showed us. I created the destination in Cloud Froundry

      also I set up mta.yml file

      then I set up xs-app.json file

      now I treating to call the distination like you did in the toturial

      but when I test the application the browser show me the following

      I don't know what I'm doing wrong I will waiting for your answer and thanks for help me

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi,

      The things that I see in your screenshots looks right so I would assume that the problem is not related to your code but actually to your destination. I tried to open the URL from your first screenshot with my browser and I also get a 404 response.

      So please make sure the app is running and the destination is set up correctly. Then, please follow the instructions from the linked video above to test your destination.

       

       

      Author's profile photo Johan Gaitán
      Johan Gaitán

      Hi Marius,

      Yeah. you were right the destination was wrong, but when I fix it:

      then I test the application again but I still get the issue:

      the app is running link_api  is weird I don't know what't going on

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Now that the destination is fixed, did you create a new project? Maybe the old project is still using the invalid destination configuration.

      Author's profile photo Johan Gaitán
      Johan Gaitán

      Marius I followed the following tutorial tutorial_link that shows how to migrate a NEO application to Cloud Foundry there says that I have to create a new project to be able to move the old project... I don't know if that's what you mean.

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      I'd suggest that you use the wizard to create a new application from the scratch (as shown in the video) and then compare the manifest.json file of that application with yours. This is probably the easiest way to see what is missing.

      Author's profile photo Johan Gaitán
      Johan Gaitán

      I saw the video and the git_link application repository nowhere is a manifest.json file, however, I created an SAPUI5 application using the wizard, and compared the manifes.json files, but both look so similar, the only difference between them is this:

       

      migration application

      new SAPUI5 application

       

       

      Author's profile photo Martin Donadio
      Martin Donadio

      Hi Marius,

      I'm just curious about one thing.

      In this example, you don't bind the NodeJS module to a connectivity service. Is this because your destination is not pointing to an On-Prem resource ? I mean, because your destination points to Internet proxy type?

      Thanks for this great post !! Very valuable 🙂

      Best regards,

      Martin

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Martin,

      correct. I don't require a binding to the connectivity service because I'm not accessing an on-prem destination (via principle propagation) here.

      Author's profile photo Ruben Alvarez
      Ruben Alvarez

      Hi Marius,

      I have created a ui5 app by yo command:

      yo easy-ui5 project.

      This app uses a destination, when I run it locally it works fine but when I display it in cf the request gives error 404.

      The app is shown in HTML5 apps  subaccount and in space Foundry the following instances are created

       

      I don't know what I'm doing wrong.

      I will waiting for your answer and thanks for help me

      Thanks

      File xs-app.json in webapp folder:

      {
        "welcomeFile": "/index.html",
        "routes": [
          {
            "source": "^/sap/opu/odata/sap/(.*)$",
            "authenticationType": "none",
            "destination": "euroberry_s4h",
            "csrfProtection": false
          },
          {
            "source": "^/user-api/currentUser$",
            "target": "/currentUser",
            "service": "sap-approuter-userapi"
          },
          {
            "source": "^(.*)",
            "target": "$1",
            "authenticationType": "xsuaa",
            "service": "html5-apps-repo-rt"
          }
        ]
      }
      MTA.yml
      ID: segcal
      _schema-version: 3.2.0
      version: 0.0.1
      parameters:
        enable-parallel-deployments: true
      modules:
        - name: webapp_deployer
          type: com.sap.application.content
          path: deployer
          requires:
            - name: segcal_html5_repo_host
              parameters:
                content-target: true
          build-parameters:
            build-result: resources
            requires:
              - name: uimodule
                artifacts:
                  - dist/uimodule.zip
                target-path: resources/
        - name: segcaldestination-content
          type: com.sap.application.content
          build-parameters:
            no-source: true
          requires:
            - name: segcal_uaa
              parameters:
                service-key:
                  name: segcal_uaa-key
            - name: segcal_html5_repo_host
              parameters:
                service-key:
                  name: segcal_html5_repo_host-key
            - name: segcal_destination
              parameters:
                content-target: true
          parameters:
            content:
              instance:
                existing_destinations_policy: update
                destinations:
                  - Name: segcal_html5_repo_host
                    ServiceInstanceName: segcal_html5_repo_host
                    ServiceKeyName: segcal_html5_repo_host-key
                    sap.cloud.service: segcal.service
                  - Name: segcal_uaa
                    Authentication: OAuth2UserTokenExchange
                    ServiceInstanceName: segcal_uaa
                    ServiceKeyName: segcal_uaa-key
                    sap.cloud.service: segcal.service
        - name: uimodule
          type: html5
          path: uimodule
          build-parameters:
            builder: custom
            commands:
              - npm run build:uimodule --prefix ..
            supported-platforms: []
      resources:
        - name: segcal_destination
          type: org.cloudfoundry.managed-service
          parameters:
            service-plan: lite
            service: destination
            config:
              HTML5Runtime_enabled: true
              version: 1.0.0
        - name: segcal_html5_repo_host
          type: org.cloudfoundry.managed-service
          parameters:
            service-plan: app-host
            service: html5-apps-repo
            config:
              sizeLimit: 2
        - name: segcal_uaa
          type: org.cloudfoundry.managed-service
          parameters:
            path: ./xs-security.json
            service-plan: application
            service: xsuaa
      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      My guess is that the xs-app.json config is incorrect. It could mean that either of the routes is wrong. Please have a look at the log of the approuter to find more hints.

      Author's profile photo Fabrice Garnier
      Fabrice Garnier

      Hi Marius,

      I have created an UI5 app (not MTA) in BAS with the option to add the application to managed application router in a CF environment.

      In BTP I have a destination to an OnPremise system:

      This system doesn't have a gateway, but I just want to consume a REST web service in it:

      http://****.entreprise.dom:1443/sap/ZFiori_WS/SO_Get

       

      In my application, I add this code in xs-app.json:

          {
            "source": "^/Fiori_WS/(.*)$",
            "target": "/sap/ZFiori_WS/$1",
            "authenticationType": "xsuaa",
            "csrfProtection": false,
      	  "destination": "Fiori_WS"
          }

      And I use the following code in the controller:

      const cWs = "Fiori_WS/SO_Get";
      
      _WsGetInit: function () {
      	var xhttp = new XMLHttpRequest();
      
      	xhttp.onreadystatechange = function () {
      		if (this.readyState == 4) {
      			MessageBox.information(this.responseText);
      		}
      	};
      
      	var vUrl = cWs + "?Action=GetInit";
      	xhttp.open("GET", vUrl, true);
      
      	xhttp.send();
      },

      My problem is if I test the application in CF (via HTML5 applications tab in my subaccount), it's ok, the app consume the web service.

      In the launchpad service, I can see the app with the content provider and add it to my launchpad, but then I get a 404 error not found when the app try to consume the web service...

      I don't see what is missing. It should be pretty simple.
      In the BAS terminal I can access the web service, in CF too but not in launchpad service

      If you have any idea, it will be helpful !

      Thanks

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      Hi Fabrice,

      the setup you described sounds good to me. And given that it works via the HTML5 Apps tab, I don't think your coding causes this problem. I'd suggest opening a issue so that someone from the Launchpad team can have a look.

       

      Author's profile photo Fabrice Garnier
      Fabrice Garnier

      Thanks for your quick answer!
      I will open an issue

      Author's profile photo Eric Gleiss
      Eric Gleiss

      Hi Marius,

      is there also an (e.g. cloud foundry based) API to update destinations without using the actual destination service? Let's say, I would like to update some destinations of several subaccounts automatically from a pipeline, but without authenticating against the destination service?
      Thanks and best regards,
      Eric

      Author's profile photo Marius Obert
      Marius Obert
      Blog Post Author

      You'll always need to interact with the destination service if you want to add or edit destination entires. But there is a way to delegate these tasks to the CF deploy service. If you do this, the destination definition can be encoded in the mta.yaml file. Follow this link to a GitHub repo to see how it can be used.

      Author's profile photo Huseyin Yalcin
      Huseyin Yalcin

      Hi Marius,

      I checked everything and every way before asking you believe me, but i have still a problem about consuming data from my odata service, let me explain my case and i would be appreciated if you give a hand.

      This is the data service which I want to consume in a UI5 application.

      https://xxx.cfapps.eu10.hana.ondemand.com/api/outbound/odata/v1/com.emea.gtt.app.gttft1.gttft1Service

      When i give the technical username and password, i can consume it in incognito session in a browser without any restriction normally.

      Here is my destination definition in the cloud.

      URL was entered with just host name : https://xxx.cfapps.eu10.hana.ondemand.com

       

      Here xs-app.json configuration.

      I also tried to set the target as just '$1' and it didn't work.

      Here mta.yaml resources.

      And the app is running on the cloud in a multi-environment as below.

       

      But i always receive 404 when i try to retrieve metadata.xml.

      What is wrong in my set up? What should be the authType in xs-app.json when i define the route?

      I also defined the same destination inside destination service which is bind to the app.but it didn't work again.

       

      Thanks in advance for all support and guidance.

      Author's profile photo matias favale
      matias favale

      Hi Yalcin. I have the same problem and same configuration.

      It works for me on local test, but when i deploy, i recive not found.

      Could you find the solution?

      Thanks

      Author's profile photo Huseyin Yalcin
      Huseyin Yalcin

      Hi Matias,

      Unfortunately, I couldn't find any solution yet, as i said, it is quite weird. My endpoint works everywhere with user auth. And in the NEO environment. But I am not able to consume it in CloudFoundry.

      Author's profile photo Satyajit Narkhede
      Satyajit Narkhede

      HI Marius Obert

      Could you please share blog on "

      Using the destination service in the frontend (= SAPUI5 web apps)

      "

      with XSUAA auth in API and consuming in SAPUI5

      Author's profile photo Kevin Dass
      Kevin Dass

      Marius Obert Firstly amazing blog and appreciate all of your contents.

      I have being working on SAP-samples /multi-cloud-html5-apps-samples for a while now and exploring destination service . It has given me a better understanding with apps in different flavors on BTP-CF.

      We all start with Northwind Odata and all goes well. However I did explore REST API example https://reqres.in/ and it works well while running on SAP BAS. However when deployed on CF and configured on Launchpad Service it has issues connecting to destination.

      I did a lot of reading on SAP blogs and many samples. However, didn't get a solve yet/ I am sure I am missing something w.r.t destination service.

      I have posted question as well https://answers.sap.com/questions/13761787/sap-btp-launchpad-services-integrate-the-rest-api.html

      I would highly appreciate if you could assist me here.

      Regards,
      Kevin Dass

      Author's profile photo Huba Erdoes
      Huba Erdoes

      Hello,

      I used your javascript code snippet in a CAP app to send a request to another CAP app via a destination. This destination uses OAuth2UserTokenExchange authentication.

      Everything works well until step 4.

      Here, when I get a value in the oDestination variable, the token looks like this:

      "authTokens":[{"type":"","value":"","error":"Retrieval of OAuthToken failed due to: Unable to fetch refresh token from the specified token service URL. Response was: Insufficient scope for this resource","expires_in":"0"}]
      Can you please give some hint or solution what is the missing piece here?
      I tried to configure both app's xs-security.json based on Add Authentication and Functional Authorization Checks to Your Application, but nothing helped.
      best regards,
      Huba Erdős