Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
kallolathome
Active Participant

Introduction


I've checked blog-posts for accessing the destinations having authentication OAuth2ClientCredentials in Cloud Foundry via Node.js . But I didn't find any code working properly.

Then I came across iobert's blog post about Using the Destination service in SAP BTP, Cloud Foundry Environment. The blog-post is really very nice and helpful. But there was one problem. The library: request used is deprecated.

So, thought of rewriting the code using the axios library. The sample code snippet is provided below for reference.

Pre-requisites:  Please bind your application with the instances of Destination Service & Authorization and Trust Management Service respectively.

Solution


// imports
const express = require("express");
const cfenv = require('cfenv');
const axios = require("axios");

const app = express();
const PORT = process.env.PORT || 4000;

const getProjectDef = async (req, res) => {

const MAX_ROWS = "1000";

// Get the UAA and destination services
const UAA_SERVICE = cfenv.getAppEnv().getService('UAA_INSTANCE_NAME');
const DESTINATION_SERVICE = cfenv.getAppEnv().getService('DESTINATION_SERVICE_NAME');

// Combine the client ID and secret for the UAA service into a single string
const UAA_CREDENTIALS = DESTINATION_SERVICE.credentials.clientid + ':' + DESTINATION_SERVICE.credentials.clientsecret;

// Set the name of the destination to retrieve and the endpoint to call
const DESTINATION_NAME = 'DESTINATION_NAME';
const END_POINT = 'END_POINT_URL';

// Set the payload for the POST request to the UAA to get a token
const post_payload = {
'client_id': DESTINATION_SERVICE.credentials.clientid,
'grant_type': 'client_credentials'
};

// Set the configuration options for the POST request to the UAA
const post_config = {
method: 'POST',
url: UAA_SERVICE.credentials.url + '/oauth/token',
headers: {
'Authorization': 'Basic ' + Buffer.from(UAA_CREDENTIALS).toString('base64'), // Encode the client ID and secret as base64
'Content-type': 'application/x-www-form-urlencoded'
},
data: new URLSearchParams(post_payload).toString() // Encode the payload as x-www-form-urlencoded
};

// Make the POST request to the UAA to get a token
axios(post_config)
.then((response) => {
if (response.status === 200) {
const token = response.data.access_token; // Get the token from the response data
// Set the configuration options for the GET request to the destination service
const get_config = {
method: 'GET',
url: DESTINATION_SERVICE.credentials.uri + '/destination-configuration/v1/destinations/' + DESTINATION_NAME,
headers: {
'Authorization': 'Bearer ' + token // Include the token in the authorization header of the GET request
}
};

// Make the GET request to the destination service to retrieve the destination configuration
axios(get_config)
.then((response) => {
const DESTINATION = response.data; // Get the destination configuration from the response data

// Get the auth token from the destination configuration
const token = DESTINATION.authTokens[0];

// Set the configuration options for the POST request to the endpoint of the destination service
// a CPI is built over the BAPI: BAPI_PROJECTDEF_GETLIST with OAuth2ClientCredentials authentication
const options = {
method: 'POST',
url: DESTINATION.destinationConfiguration.URL + END_POINT,
headers: {
'Authorization': `${token.type} ${token.value}` // Include the auth token in the authorization header of the GET request
},
data: {
MaxRows: MAX_ROWS,
ProjectDefinitionRange: {
item: [
{
Sign: req.data.sign,
Option: req.data.option,
Low: req.data.low,
High: req.data.high,
},
],
},
}
};

// Make the GET request to the endpoint of the destination service
axios(options)
.then((response) => {
res.send(response.data); // Return data
})
.catch((error) => {
res.send(error); // Return error
});
})
.catch((error) => {
res.send(error); // Return error
});
}
})
.catch((error) => {
res.send(error); // Return error
});
console.log('Exit :------->');
};

// endpoint
app.get("/getProjectDef", getProjectDef);

app.listen(PORT),
() => {
console.log(`Listnening to the PORT: ${PORT}`);
};

 

N.B: This code snippet can be easily used in the CAPM(Node.js) applications. There is another library named sap-cf-axios which can be used if you want to code less.

 

Happy Coding!
6 Comments
Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
Hi Kallol,

We advise developers to use the CAP framework for any SAP side-by-side developments. Consuming the destination service is a built-in feature of CAP:

This would greatly simplify the approach.
mauriciolauffer
Contributor
One could use any of the hundreds packages available in NPM for that, axios is just another one... Something to consider before doing what's suggested in the blog:

  1. If you're using CAP, follow Willem comments;

  2. You don't need any library/package for HTTP requests, just use native APIs such as fetch;

  3. If you do want to use a library to consume BTP destinations, @sap-cloud-sdk/connectivity is a much better option for its built for it, not a generic HTTP client.

drvup
Contributor
Hi kallolathome ,

your approach is good and useful, but - in some kind - outdated. Don't worry, the speed of innovation within the context of BTP and all surrounded is enormous and it's though to keep on track.

Check out all the details about the SAP Cloud SDK; it's providing all these things and capabilities out of the box 🙂

 

btw: I did start with the same approach and doing it in pure javascript back in 2016; I really do recommend spending time with typescript - It will make your life as a developer easier and provide you a bunch of flowers of features and tools within 🙂
kallolathome
Active Participant
0 Kudos

Thanks cedvup for checking out my blogpost.Yes, the plan now is to learn Typescript

i838713
Advisor
Advisor
0 Kudos
Hi Willem!

Thanks very much!

Sadly, as much as I have tried following those tutorials, I just can't get it to work.

I have a fully working CAP application, but I'm unable to access the destinations I have created on BTP either locally or when deployed to the cloud.

Can you you please recommend some other resource or sample I could look at?

I have done a considerable amount of research already.
Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
0 Kudos
Hi Gustavo,

Have a look at my answer on a different question: https://answers.sap.com/questions/13910674/sap-btp-cap-how-to-trigger-or-cancel-workflow-from.html?c...

Additionally, you will need to bind your application with both a destination service instance and xsuaa, and then everything should work.

If you still face issues, feel free to share your git with me via SAP email.
Labels in this area