Skip to Content
Technical Articles

Using the Destination service in the Cloud Foundry Environment

In this blog post, I will briefly explain why there are ‘destinations’ in the SAP Cloud Platform. 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 Cloud Platform 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 Cloud Platform 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).

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 code base

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 does this translate to the “Cloud Foundry world”?

The previous section did not only show that information about the endpoints should be stored centrally, 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 them 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 web server which delivered this script.

The most common workaround is sending a request to your web server, which proxies the request to the final destination. In the SAP Cloud Platform on the other side, you don’t need to bother at all! The runtime environment 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 Cloud Platform 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. Make sure both services are bound to the app in the mta.yml file (SAP Web IDE should create those entries by default):
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 (and Neo) 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 into this process and prove that’s it’s actually quite simple.

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