Skip to Content
Technical Articles

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.

96 Comments
You must be Logged on to comment or reply to a post.
  • 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

    • 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

      • 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

    • 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

  • 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

    • 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

      • 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

        • 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

    • 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

      • 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

        • 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 🙂

          • 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

          • 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

          • 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

          • 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.

             

  • 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

     

    • 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!

  • 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.

    • 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.

      • 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.

         

          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.

          • 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
            }
            }
          • 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.

          • 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.

             

          • 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.

          • Hi Marius,

            I got the answer really thanks for your great support.

            Cloud connector between the backend system is the problem.

            Thank you.

             

             

    • 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.

  • 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

    • 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

      • 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

  • 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

  • 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.

     

     

    • 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.

       

  • 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

     

     

    /
    • 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.

      • 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.

        • 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

  • 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

  • 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

    • 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.

      • 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

      • /
        • 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.

  • 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

    • 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?

      • 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

        • 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).

          • 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!

          • 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.

             

          • 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!

            /
            coding%20in%20webIDE
  • 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

     

     

     

    • 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.

      • 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

         

  • 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

    /
    CF%20Destination%20%28backend%29
  • 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

     

     

     

     

     

    • 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.

      • 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
        • 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".

          • 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. 
              
            /
            destination%20attribute
          • 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.

          • 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

          • /
          • 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!

             

          • 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!. 

             

             

          • 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 🙂

          • 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.

          • 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