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. 

Challenge:

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%20instance%20creation

Job instance creation

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

Go%20to%20Dashboard%20from%20Job%20Instance

Go to Dashboard from Job Instance

Step 2: Create your job

Create%20your%20job

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%20details

job details

job%20action%20details

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%20Schedule

Create Schedule

Schedule information:

Schedule%20Information

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%20Inputs

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?

Appendix

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 = "https://e70506aa-ddc0-435c-aab6-7abc40008538.abap.eu10.hana.ondemand.com/sap/opu/odata/sap/ZSB_SO_HDR/header";

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) => {
                resolve({
                    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"
            }

        }

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

    _getAccessToken()
        .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 Carlos 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:

Assumptions:

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

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x