Skip to Content
Technical Articles
Author's profile photo Somnath Paul

BTP Background Job Scheduling | Consume RAP Service from BTP (Node JS)


Job Scheduling is nothing new for us being an ABAPer and with SM36/37 or even programmatically we submit jobs, so now the question is how to use the same job scheduling from BTP.

Obviously leveraging a service available for the same. Challenge was a little more for me when I had to perform certain on-prem table updates from a RAP service and that too through BTP job scheduling.

But here for my readers, first of all, I must say, the current blog post is NOT talking about how to update the on-prem custom table from BTP, but more on a simpler use case, about how to consume a RAP service and fetch certain data though a background job scheduling process. So if you are not interested now, a good time to skip this blog post, otherwise let us move to understand different steps. Anyways, I will talk at the end of this blog post about an approach that I tried to update the on-prem table using RAP service (in a short way).

If you prefer to watch the topic rather reading it, I also have shared the video URL for your convenience. You can find it at the end of this blog post. 


Calling a RAP service demands certain OAuth Authentication things to consider.

This means, we need some token and this is nothing but JWT (JSON Web Token) is needed to authenticate the RAP service. Hmm, but that’s fine, we have XSUAA service for that and I can use that for authentication purposes so what is the concern?

But we will be scheduling this job as a background, so the dialog user is not there to help with the Authentication process, which means we have to generate the JWT token programmatically.

Step1: Create service instance for BTP Job Scheduler

From the BTP service instance search for JOB and create an instance for the service.


Job instance creation

Now the service instance you can find from the instance section and click on the Dashboard option as marked


Go to Dashboard from Job Instance

Step 2: Create your job


Create your job

Here you have to give a logical job name and an important thing to note HTTP Method option, here you need to choose the verb you want for your scenario. For our scenario, we will select the default ‘GET’ because we just need to fetch certain data through a RAP service. So here the action input field will contain the actual service endpoint which this background job will call to fetch some data.

But we don’t have this service built yet!

True, so we will come back to this step completion once we are done with the service build-up.

We will create a node js application within which we will call our RAP service and also handle the authentication part. In the Appendix section, you can find the code snippet. I will explain in detail soon, but for the blog’s continuation let’s assume I have the service URL and put the same in the action field.

I create the job with a simple name as “rapjobdemo” as below and now click on this job name to perform Step 3


job details


job action details

**Action URL: we will create it soon as promised!

Step 3: Scheduling

Now job gets created and we need to complete the scheduling part now.


Create Schedule

Schedule information:


Schedule Information

Here Pattern provides you various options to schedule and in our case, default One Time is sufficient. Now comes the value part, here we will put it as ‘now’ because I want to trigger the job immediately. if you want to know various other available scheduling options, here is the link.

You can very get the purpose for Data (JSON) part I believe, as this will be used while we want to pass certain payload during our POST operation.

So our input should be as like this:


Scheduling Inputs

Alright! So if our service URL (Action field URL) is working fine, this will be able to trigger the job and fetch data like this:

You need to click on the “Run Logs” (left side pane) and will show below screen detail page as below:

Now click on the glass icon, and this will show you the response payload, cool!! simple isn’t it?


Now as promised, here is the node js code snippet

const oauthClient = require("client-oauth2")
const express = require("express");
const request = require("request-promise");
const env = require("dotenv").config();
const e = require("express");

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

//Use your RAP service URL here & make sure you remove "web" part from below RAP URL
//after .abap

const SERVICE_URL = "";

const VCAP_SERVICES = JSON.parse(process.env.VCAP_SERVICES);
const XSUAA_CLIENTID = VCAP_SERVICES.xsuaa[0].credentials.clientid;
const XSUAA_CLIENTSECRET = VCAP_SERVICES.xsuaa[0].credentials.clientsecret;
const XSUAA_URL = VCAP_SERVICES.xsuaa[0].credentials.url;

const _getAccessToken = () => {
    return new Promise((resolve, reject) => {
        const client = new oauthClient({
            accessTokenUri: XSUAA_URL + '/oauth/token',
            clientId: XSUAA_CLIENTID,
            clientSecret: XSUAA_CLIENTSECRET,
            scopes: []

        client.owner.getToken(process.env.USER_EMAIL, process.env.PASSWORD)
            .catch((error) => {
                reject({ message: 'Error in getting access token', error: error });
            .then((result) => {
                    accessToken: result.accessToken

const makeQuery = (serviceUrl, accessToken) => {
    return new Promise((resolve, reject) => {
        const options = {
            url: serviceUrl,
            resolveWithFullResponse: true,
            headers: {
                Authorization: "Bearer " + accessToken,
                Accept: "application/json"


            .then((response) => {
                if (response && response.statusCode == 200) {
                        responseBody: response.body
                reject({ message: 'Error while calling RAP Service' });
            .catch((error) => {
                    message: 'Failed to receive RAP details',
                    error: error
app.get('/header', (req, res) => {

        .then((result) => {
            return makeQuery(SERVICE_URL, result.accessToken)
        .then((result) => {
            res.send('<p> Result from RAP Service' + JSON.stringify(result.responseBody) + '</p>');
        .catch((error) => {
            res.send('ERROR' + error.message + 'FULL ERROR' + error.error)
app.listen(PORT, console.log(`Listening on port ${PORT}`));

**** I followed an interesting blog post from Carload Roggan and developed the node js part. Thanks to Carlos for sharing such rich content.

The complete project details you can find here.

Please follow the readme section of the project to know how to clone and deploy the application to the BTP cloud.

Certain important things are still there (like XSUAA service creation and linking the Role etc), which you definitely need to know to make it work successfully and so thought to share a video discussion that i published recently on my youtube channel.

Now how to post data to the on-prem table:


The destination is created and the on-prem system is connected with a cloud connector

  • Next, get the metadata from the backend OData service which has the capability to update table records.
  • import the same metadata into the RAP project & create a custom entity
  • Expose this entity and now this is simply a part of your RAP project and add the behavioral capabilities
  • The class handler for your Custom entity will be doing the rest of the magic to call backend service and update records
  • If you need to post some default values thru background job, obviously you need to use the Data (JSON) section as I mentioned above

Tried to create a short demo, about how to consume external services from the RAP service, and here is the video URL for your reference:

Thanks for reading as well as for watching, and share your feedback, suggestions (if any).

Happy Learning!

With Regards, Somnath

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Carlos Roggan
      Carlos Roggan

      Great Blog and video, Somnath Paul !
      I'm glad that my jobscheduler post was helpful 😉
      Keep rocking, Somnath!

      Author's profile photo Somnath Paul
      Somnath Paul
      Blog Post Author

      Thanks, Carlos!, this is really inspiring! 🙂

      Author's profile photo Thomas Jung
      Thomas Jung

      Very nice and thank you for sharing your experience.  Can I make one suggestion for the Node.js coding part?  Instead of parsing the process.env.VCAP_SERVICES directly, consider using the SAP supplied Node.js module @sap/xsenv for this. @sap/xsenv - npm (

      It will provide you with more flexibility. For instance looking up the service instance details by tag. But more importantly this module provides a consistent and abstracted approach to access the information on XSA, SAP BTP Cloud Foundry, or SAP BTP Kyma/K8S. Particularly the later two might be of interest to code in the future you might want to run in either or both of these runtimes. It also has some development convenience features like using a default-env.json file during local development to simulate bindings/environment.

      Author's profile photo Somnath Paul
      Somnath Paul
      Blog Post Author

      Many Thanks, Thomas Jung for sharing your thoughts. I will try to update this blog post soon with the approach that you have mentioned. Thanks Again!

      Author's profile photo Mark Teichmann
      Mark Teichmann

      Another idea would be to use SAP Cloud SDK for the connection. It is the standard solution provided by SAP and really easy to use.