Skip to Content
Author's profile photo Sreehari V Pillai

OData CRUD from XSJS-Outbound API

  OData CRUD from XSJS-Outbound API  

     SAP HANA Extended Application Services (SAP HANA XS) includes a server-side JavaScript API that enables outbound access to a defined HTTP destination. The HTTP destination provides services which an application can use. In the following steps , we will configure the connectivity with netweaver gateway system which provides us a Employee Odata service where we can C,R,U & D Employee details.

Step 1 : Create a XS Project in the project perspective.


     Create a XS project in the project explorer, maintaine .xsaccess file and .xsapp files and create four individual xsjs files for CRUD operations. After this step , our project hierarchy will look like below.

project1.JPG

Step 2 : Create a XS HTTP Connection parameters.


     Maintain a folder under the main project level named service, inside which we can maintain our connectivity parameters to the net weaver gateway.

Create a file named gateway.httpdest with the connection parameters as below.


host = “Target IP Address”;

port = Target Host;

description = “ABAP Gateway test”;

pathPrefix = “/sap/opu/odata/sap/ZEMPLOYEE_SRV”;

authType = none;

useProxy = false;

proxyHost = “”;

proxyPort = 0;

timeout = 0;

Step 3 : Implement GetEntity.xsjs.

          Here in this file, we will implement the Read operation on the Odata URL.


var destination;
var client;
var request;
var employeeID;
//Read the input employee number which is to be read
employeeID = $.request.parameters.get("EMPID");
try{
    //Reading the destination properties
    destination = $.net.http.readDestination("CRUD.service","gateway");
    //Creating HTTP Client
    client = new $.net.http.Client();
    //Creating Request
    request = new $.web.WebRequest($.net.http.GET,"Employee('"+employeeID+"')?$format=json");
    client.request(request,destination);
    //Getting the response body and setting as output data
    $.response.setBody(client.getResponse().body.asString());
}
catch(errorObj){
  $.response.setBody(JSON.stringify({
  ERROR : errorObj.message
  }));
}

Output :

GetEntity.JPG

Step 3 : Implement CreateEntity.xsjs.


     When an OData POST (Create) call is made, it is very much important to manage the Cross site request forgery by handling CSRF tokens(en.wikipedia.org/wiki/Cross-site_request_forgery ).

In order to make a POST call, we can trigger a GET(Read) request to the gateway system with the header “X-CSRF-Token” , and can use the returned CSRF Token.

getCSRF() function would return the CSRF Token to make the POST call. We can implement this method in the file CreateEntity.xsjs


var destination;
var client;
destination = $.net.http.readDestination("CRUD.service","gateway");
client = new $.net.http.Client();
function getCSRF()
{
  var request;
  var response;
  try{
    //GET Operation on the base odata URL
    request = new $.web.WebRequest($.net.http.GET,"/");
    //X-CSRF-Token header will be set with value Fetch
    request.headers.set("X-CSRF-Token", "Fetch");
    client.request(request,destination);
    response = client.getResponse();
    //reading the token from response header
    return response.headers.get("X-CSRF-Token").toString();
  }
  catch(errorObj){
  $.response.setBody(JSON.stringify({
  ERROR : errorObj.message
  }));
  return "CSRF TOKEN FETCH FAILED : " + errorObj.message;
  }
}

Implementing the POST Method call :


function makePOSTCall(CSRF){
  //Specifying the entity name for the POST operation
  var request = new $.web.WebRequest($.net.http.POST,"/Employee");
  try{
  //Setting the token header
  request.headers.set("x-csrf-token",CSRF);
  //Application content type
  request.headers.set("Content-Type","application/json");
  request.headers.set("X-Requested-With","XMLHttpRequest");
  //setting the data to be created
  request.setBody(JSON.stringify(
  {
  d: {
  Empid:"0000006000",
  Ename:"RAHUL GANDHI",
  Phone:"00000999999999"
  }
  }));
  client.request(request, destination);
  //Checking the status ( 201 for success )
return client.getResponse().status;// === '201' ? "Successfully Created" : "Not created:";
  }
  catch(eee){
  return "Error:"+eee.message;
  }
}
$.response.setBody(makePOSTCall(getCSRF()));

Output :

created.JPG

Step 4 : Implement DeleteEntity.xsjs.

    

     To DELETE an entity , we need to specify the Entity Key which is to be deleted and the OData operation DEL. For deletion, we do not need to pass any body as the body is irrelevant for the operation.


function deleteEmployee(CSRF){
  try{
  destination = $.net.http.readDestination("CRUD.service","gateway");
  client = new $.net.http.Client();
  //Specifying the entity name for the DELETE operation
  var request = new $.web.WebRequest($.net.http.DEL,"/Employee('"+employeeID+"')");
  //Setting the token header
  request.headers.set("x-csrf-token",CSRF);
  //Application content type
  request.headers.set("Content-Type","application/json");
  request.headers.set("X-Requested-With","XMLHttpRequest");
  client.request(request, destination);
  //Checking the status ( 204 for successful deletion )

  return client.getResponse().status;
  }
  catch(eee){
  return "Error:"+eee.message;
  }
}
$.response.setBody(deleteEmployee(getCSRF()));

We can use the same getCSRF() function used in CreateEntity.xsjs, her also.

Output :

deleted.JPG

Step 5 : Implement UpdateEntity.xsjs.


     While updating an entity , specify the key value of the entity to be updated and the new entity data in the http body.


function makePOSTCall(CSRF){
  //Specifying the entity name for the PUT operation
  var request = new $.web.WebRequest($.net.http.PUT,"/Employee('0000001000')");
  try{
  //Setting the token header
  request.headers.set("x-csrf-token",CSRF);
  //Application content type
  request.headers.set("Content-Type","application/json");
  request.headers.set("X-Requested-With","XMLHttpRequest");
  //setting the data to be created
  request.setBody(JSON.stringify(
  {
  d: {
  Empid:"0000001000",
  Ename:"Name Changed",
  Phone:"00000999999000"
  }
  }));
  client.request(request, destination);
  //Checking the status ( 204 for success )
  return client.getResponse().status;// === '204' ? "Successfully Created" : "Not created:";
  }
  catch(eee){
  return "Error:"+eee.message;
  }
}
$.response.setBody(makePOSTCall(getCSRF()));

Output :

updates.JPG

References :

odata.org,SAP HANA Developer guide

Regards

Sreehari V Pillai

“Save Nature For the Future”

Assigned Tags

      16 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Krishna Kishor Kammaje
      Krishna Kishor Kammaje

      Sreehari,

      While connecting to Gateway, I do not see you authenticating with Gateway.

      How is authentication happening here to Gateway?

      Author's profile photo Sreehari V Pillai
      Sreehari V Pillai
      Blog Post Author

      Krishna,

      For this case, I hard coded the credentials in the SICF node itself.

      Sreehari

      Author's profile photo Former Member
      Former Member

      Hello,

      Sreehari V Pillai

      Thanks for the nice blog. Could you please throw some light on this one? Call ABAP function modules from HANA. Just to make sure I am on the right path.

      Thanks

      Sangamesh

      Author's profile photo Former Member
      Former Member

      Hi,

      Thank you very much for sharing your knowledge; Secondly you colaborarme the following drawback could?

      http://scn.sap.com/thread/3868344

      Regards.

      Author's profile photo Sreehari V Pillai
      Sreehari V Pillai
      Blog Post Author

      no donuts 🙁

      Author's profile photo Uttam Kumar
      Uttam Kumar

      Hi Sreehari,

      I have created xshttpdest and xsjs file. My requirement is to read the odata service from the xsjs file.

      While running the xsjs file one extra "/" is added in the service url after hostname from where i want to get the data and the xsjs file is giving below error

      {"ERROR":"HttpClient.request: request failed: response from xxxxxxx/:80/sap/opu/odata/iwpgw/TASKPROCESSING;v=2/TaskCollection('83')/Description is pending...please retrieve it first with getResponse()"}

      I want to create this url

      xxxxxxx:80/sap/opu/odata/iwpgw/TASKPROCESSING;v=2/TaskCollection('83')/Description

      "hostname:port/pathprefix"

      Please let me know how to remove "/" after hostname.

      Destination code:

      host ="xxxxxxx";
      port =80;
      description ="ABAP Gateway test";
      pathPrefix ="sap/opu/odata/iwpgw/TASKPROCESSING;v=2/TaskCollection('83')/Description";
      authType =basic;
      timeout =0;

       

      xsjs code

      try{
          //Reading the destination properties
          destination = $.net.http.readDestination("test12.Services","dest00");
          //Creating HTTP Client
          client = new $.net.http.Client();
          //Creating Request
         
          request = new $.web.WebRequest($.net.http.GET,"?$format=json");
          
          client.request(request,destination);
          $.response.setBody(client.getResponse().body.asString());
      }
      catch(errorObj){
       $.response.setBody(JSON.stringify({
        ERROR : errorObj.message
        }));
      }

       

      Author's profile photo Sreehari V Pillai
      Sreehari V Pillai
      Blog Post Author

      Hi,

      sorry for late reply . I wasn’t around for  while . Were you able to solve this ? If not , will look into it .

      sree

       

      Author's profile photo Former Member
      Former Member

      Hi,

       

      I am new to sap technology. Basically i am from UNITY3D .NET background. I got a requirement to consume a xsodata service which uses client certificate to authenticate. In regular .net project i am able to get the data but the same is not working when used in UNITY. Getting 403 forbidden error.

      So i was thinking of using an xsjs service which will load the client certificate and gets me the data. Is there a way to do it? Kindly reply asap.

       

      thanks

       

      Author's profile photo Former Member
      Former Member

      Hi Sree,

      thanks for sharing this post! I am also new to the sap technology. I have created the "gateway.httpdest" file, but where can i find the "pathPrefix"? In my case i want to send a webrequest from a xsjs file to a xsodata file which are both located in the same tree. if i use: pathPrefix="/Package/Package/TSA.xsodata" i get this error: "The requested URL /TSAPI/xsodata/TSA.xsodataId('2' was not found on this server."

      I really hope you can help me out with this.

      thanks in advance

      Author's profile photo Sreehari V Pillai
      Sreehari V Pillai
      Blog Post Author

       

      So, you want to send a request from XSJS to XSODATA . Well, are they the same system ? If yes - It doesn't require to consume xsodata from xsjs , instead, you can consume the model behind the xsodata directly from XSJS .

      Sticking to your question - Run the xsodata file in browser . it would be something like https://<ip>:port/package/abc/test/MYService.xsodata

       

      then /package/abc/test/MYService.xsodata is the pathPrefix.

      Sreehari

       

      Author's profile photo Amit Kumar Barik
      Amit Kumar Barik

       

      Hi Sree,

      Facing issue while executing .xsjs file. Please refer to the attached doc and help me.

       

      GetAgentLists.xsjs

      var destination;
      var client;
      var request;
      //var employeeID;
      //Read the input employee number which is to be read
      //employeeID = $.request.parameters.get(“EMPID”);
      try{
      //Reading the destination properties
      destination = $.net.http.readDestination(“ChatBot.services”, “DEST_BOT_ODATA”);
      //Creating HTTP Client
      client = new $.net.http.Client();
      //Creating Request
      request = new $.web.WebRequest($.net.http.GET, “/PurchaseOrderSet(‘4500000405’)”);
      //request.headers.set(“x-csrf-token”,CSRF);
      client.request(request,destination);
      //Getting the response body and setting as output data
      $.response.setBody(client.getResponse().body.asString());
      }
      catch(errorObj){
      $.response.setBody(JSON.stringify({
      ERROR : errorObj.message
      }));
      }

       

      Xshttpdest file:

      description = “PO_Details”;
      //host = “aaesaws0521.aaes.XXXXXXX.com”;
      host = “madap8033.XXXXXXX.tsap”;
      port = 8001;
      pathPrefix = “/sap/opu/odata/SAP/ZAB_GET_PO_STATUS_SRV”;
      authType = none;
      useProxy = false;
      proxyHost = “”;
      proxyPort = 0;
      timeout = 0;
      //useSSL = false;
      //timeout = 0;
      //sslHostCheck = false;
      //sslAuth = anonymous;

       

      Getting this error while executing .xsjs file.

      {
      “ERROR”: “HttpClient.request: request failed: internal error occurred \”Failed to send request to socket…rc = -1\””
      }

      Regards,

      Amit

      Author's profile photo Sreehari V Pillai
      Sreehari V Pillai
      Blog Post Author

      are you able to communicate to this socket from javascript / UI5 ?

      Author's profile photo Marco Harpenschläger
      Marco Harpenschläger

      Hey,

      I got the following error message:

      {“ERROR”:”read ECONNRESET”}

       

      I am using XSA and I defined the destination in the cockpit and connected the modules, it is working fine for other services, but not for mine.

      “protocol”: “https”,
      “port”: “51154”,
      “host”: “scotty-3.intern.zz”,
      “authType”: “none”,
      “pathPrefix”: “”,
      “timeout”: “0”

       

       

      This service is only available in the intranet, but this should not be an issue, should it?

      What does this error mean?

      Mayber because the connection is not save?

      BR

      Marcel

       

      Author's profile photo Sreehari V Pillai
      Sreehari V Pillai
      Blog Post Author

      Hay, some possibilities to check

      1 . Does you server has access to the url ? ask the linux admin to curl the url .
      2. Do you have an http version of the url ? try any other intranet url having an http instead of https.
      3. May be you will need to set up some host file entry in the the linux ( if 1 fails )

      Author's profile photo Marco Harpenschläger
      Marco Harpenschläger

      Thanks for the input, I will try it later.

      First I have a easier question.

      I need to user authType:"Basic".

      I tried to set user: "XXX" and password : "YYY" but it says either wrong or not user crednetials.

      How can I pass user and password to a service with authentication?

      Author's profile photo Marco Harpenschläger
      Marco Harpenschläger

      I got it,

      syntax is:

      authType:"basic"

      username:"XXX"

      BR