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.
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 :
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 :
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 :
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 :
References :
odata.org,SAP HANA Developer guide
Regards
Sreehari V Pillai
“Save Nature For the Future”
Sreehari,
While connecting to Gateway, I do not see you authenticating with Gateway.
How is authentication happening here to Gateway?
Krishna,
For this case, I hard coded the credentials in the SICF node itself.
Sreehari
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
Hi,
Thank you very much for sharing your knowledge; Secondly you colaborarme the following drawback could?
http://scn.sap.com/thread/3868344
Regards.
no donuts đ
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:
xsjs code
Hi,
sorry for late reply . I wasnât around for  while . Were you able to solve this ? If not , will look into it .
sree
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
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
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
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
are you able to communicate to this socket from javascript / UI5 ?
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
Â
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 )
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?
I got it,
syntax is:
authType:"basic"
username:"XXX"
BR