#sitHH : Exposing data to #UI5 without using SAP Gateway
This year, just a week before I’ve started my wonderful vacations in Barcelona and Alcúdia, I had again the pleasure to hold a session at SAP Inside Track Hamburg. Because I’m not able to provide the slides (I haven’t used any) I was asked to blog about it. (to satisfy someone: this means to “write a blog post” 😉 )
The Motivation
One of my current customers is implementing a new E-commerce shop and I’m responsible for the connection to the backend SAP ERP system. “Yea, again a SAP Gateway project” just came into my mind as soon as I’ve heard about it 🙂 A quick look into “System -> Status” and I realized that they are on ERP 6.0 Ehp 0 (Zero) -> no Gateway installed.
The Options
- upgrade the system to a higher Enhancement Package so SAP GW is part of the standard installation
- install SAP GW as Add-On
- something completely different
Option 1.) was completely out of budget. Sure, they have to do it sometimes in the near future, but not now and not for this reason.
For option 2.) a question came into my mind, which I was not able to answer: what happens in a later EHP upgrade, where SAP GW is part of the standard, if we already had installed SAP GW as Add-On? Will we get into trouble?
The Solution
If you know a bit of my background (I’m a little RESTifarian ), you will not be surprised that I’ve choosen ADL (Alternative Dispatcher Layer, by DJ Adams ) and zJSON (ABAP JSON document class, by me) to solve this problem. Open Source #ftw ! Links: see Appendix
SAP’s new claim is “SIMPLE”. And yes: ADL + zJSON is simple. It’s so simple, that I’m using it even for prototyping if SAP GW IS installed (because ie. the cleansing behind you is much easier).
Edit: please concider that you need an additional user license for the (anonymous) ICF user.
The Data
To make the demo a bit (more) interesting, I’ve used a DDL view instead of a table as data source:
@AbapCatalog.sqlViewName: ‘YSITHH_SO’
define view ysitHHSalesOrder as select from snwd_so as so
inner join snwd_bpa as bpa on so.buyer_guid = bpa.node_key {
key so.so_id as id,
bpa.bp_id as business_partner_id,
bpa.company_name,
substring( bpa.company_name, 1, 10 ) as company_short,
case bpa.bp_role
when ’01’ then ‘Customer’
when ’02’ then ‘Supplier’
else ‘undefined’
end as business_partner_role,
case so.billing_status
when ‘ ‘ then ‘unpaid’
else ‘paid’
end as billing_status,
@Semantics.currencyCode so.currency_code,
@Semantics.amount.currencyCode: ‘currency_code’ so.gross_amount
}
(for documentation link on DDL sources and the new openSQL syntax, see Appendix)
Test report
DATA salesorders TYPE STANDARD TABLE OF ysithhsalesorder.
SELECT * FROM ysithhsalesorder
INTO TABLE @salesorders.
cl_demo_output=>display( salesorders ).
Result
The JSON document
To translate the data in JSON format I’ve used my JSON document class.
DATA salesorders TYPE STANDARD TABLE OF ysithhsalesorder.
SELECT * FROM ysithhsalesorder
INTO TABLE @salesorders.
cl_demo_output=>display_json( zcl_json_document=>create_with_data( salesorders )–>get_json( ) ).
(you’ve noticed the method chaining? I like it. But don’t overuse it, please)
Result
The Call
Now to the REST call: the ADL implementation.
We have to create the REST dispatcher (or use an existing one) and the REST resource for the order data.
The Dispatcher
CLASS ysithh_dispatcher_test DEFINITION
PUBLIC
INHERITING FROM y_adl_disp_base
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS if_http_extension~handle_request REDEFINITION.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS YSITHH_DISPATCHER_TEST IMPLEMENTATION.
METHOD if_http_extension~handle_request.
handler( p = ‘^/SalesOrder’ h = ‘YSITHH_SALESORDER_TEST’ ).
dispatch( server ).
ENDMETHOD.
ENDCLASS.
Don’t forget to enter the dispatcher class into the ICF path via transaction SICF
The Resource
CLASS ysithh_salesorder_test DEFINITION
PUBLIC
INHERITING FROM y_adl_res_base
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS get
IMPORTING matches TYPE stringtab.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ysithh_salesorder_test IMPLEMENTATION.
METHOD get.
DATA salesorder TYPE STANDARD TABLE OF ysithhsalesorder.
SELECT * FROM ysithhsalesorder
INTO TABLE @salesorder.
response->set_cdata( zcl_json_document=>create_with_data( salesorder )–>get_json( ) ).
response->set_header_field(
EXPORTING
name = ‘Access-Control-Allow-Origin’ ” Name of the header field
value = ‘*’ ” HTTP header field value
).
ENDMETHOD.
ENDCLASS.
The Test
For a test of the service just call the resource in a browser of your choice: http://host:port/sap/bc/ysithh_test/SalesOrder
Viewed with Chrome plug-in “JSONview”
The App
Now we are able to consume the data for example in an UI5 table.
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=“X-UA-Compatible” content=”IE=edge”>
<meta http-equiv=‘Content-Type’ content=‘text/html;charset=UTF-8’/>
<script src=“resources/sap-ui-core.js”
id=“sap-ui-bootstrap”
data-sap-ui-libs=“sap.ui.commons”
data-sap-ui-theme=“sap_bluecrystal”>
</script>
<!– add sap.ui.table,sap.ui.ux3 and/or other libraries to ‘data-sap-ui-libs’ if required —>
<script>
sap.ui.localResources(“sithh_test”);
var view = sap.ui.view({id:“idmain1″, viewName:”sithh_test.main”, type:sap.ui.core.mvc.ViewType.XML});
view.placeAt(“content”);
</script>
</head>
<body class=“sapUiBody” role=”application”>
<div id=“content”></div>
</body>
</html>
main.view.xml
<core:View xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc"
xmlns:commons="sap.ui.commons"
xmlns:m="sap.m"
xmlns="sap.ui.table"
controllerName="sithh_test.main" xmlns:html="http://www.w3.org/1999/xhtml">
<Table
id="tt"
rows="{/itab}"
title="Table Example">
<columns>
<Column>
<label>
<commons:Label text="ID" />
</label>
<template>
<commons:TextField value="{id}" />
</template>
</Column>
<Column>
<label>
<commons:Label text="Company" />
</label>
<template>
<commons:TextField value="{company_short}" />
</template>
</Column>
<Column>
<label>
<commons:Label text="Role" />
</label>
<template>
<commons:TextField value="{business_partner_role}" />
</template>
</Column>
<Column>
<label>
<commons:Label text="Status" />
</label>
<template>
<commons:TextField value="{billing_status}" />
</template>
</Column>
<Column>
<label>
<commons:Label text="Currency" />
</label>
<template>
<commons:TextField value="{currency_code}" />
</template>
</Column>
<Column>
<label>
<commons:Label text="Value" />
</label>
<template>
<commons:TextField value="{gross_amount}" />
</template>
</Column>
</columns>
</Table>
</core:View>
main.controller.js
sap.ui.controller("sithh_test.main", {
onInit: function() {
var oModel = new sap.ui.model.json.JSONModel(
'http://se38-d7x-1.se38.local:8000/sap/bc/ysithh_test/SalesOrder'
);
sap.ui.getCore().setModel(oModel);
},
});
The Result
Appendix
If you wonder: SAP has changed the name of “SAP Netweaver Gateway”. It is now just “SAP Gateway”
ADL
Source: https://github.com/qmacro/ADL
Documentation: http://scn.sap.com/people/dj.adams/blog/2009/09/21/a-new-rest-handler-dispatcher-for-the-icf
JSON Document Class
Source: https://github.com/se38/zJSON/wiki/Usage-zJSON
Open UI5
DDL
New Open SQL Syntax
http://help.sap.com/abapdocu_740/en/index.htm?file=ABENNEWS-740_SP05-OPEN_SQL.htm
Hi Uwe,
Nice blog! I followed the steps and it works great. Currently I'm using the alternative described here: JSON Adapter for ABAP Function Modules
I'm not sure yet which is the best solution for my scenario.
Is it possible to use importing parameters with the ADL classes? I.e. http://host:port/sap/bc/ysithh_test/SalesOrder?billing_status="unpaid"
Regards,
Jeroen
Hi Jeroen,
yes of course. In the resource class you have the full access to the request object.
If it is an HTTP GET you can read the field via method IF_HTTP_ENTITY~GET_FORM_FIELD( "billing_status"). For a POST request, you can read the body of the request (which hopefully contains JSON 😛 ).
"I was asked to blog about it. (to satisfy someone: this means to "write a blog post" 😉 )"
Ha - brilliant, I'm sure that someone will be pleased he's got through to another person!
Cheers,
G.
Hi Uwe, nice blog.
Short feedback to all consulting companies that reads your blog: the license SAP Gateway for Consumer is not only the technical enablement to connect SAP to such a non-SAP web shop. It also contains the usage right for the web shop user (=end customer) to access indirectly SAP data without a Named User license. Several similar licenses includes similar usage rights for "consumers". I don't know the right license for your development. I personally think that it's a good idea to check the final landscape upfront with the SAP sales contact responsible for the SAP back end or the partner management for consulting companies.
See for example software use right:
http://global.sap.com/corporate-en/our-company/agreements/western-europe/software-use-rights-agreements.epx
See for example the partner program for OEM development: SAP Application Development Partner Center
Regards,
Raik
as private reader of interesting technology blogs
Hi Raik,
thank you for the advice for the additional user license. I've added this hint to the blog (chapter "Solution"). In our project we already have the license because of an already existing shop solution.
Where do you have this information from? Do you have a link?
Hi Uwe,
You could see the exception of the named user for example in the SAP store -> Gateway for Consumer -> pricing. It is mentioned in the pricing section that Administrators and Developers need a Named User. That means that "consumers" doesn't need an additional named user license while accessing SAP over this component. Other components like the SAP Mobile Platform for consumer have similar statement in the pricing section.
https://store.sap.com/sap/cp/ui/resources/store/html/SolutionDetails.html?pid=0000009470&pcnty=US
It is more clear in the SAP price list. That means that SAP sales should tell the correct answer in the context of the specific sales history of the customer.
Sales should also answer if your shop solution license includes your "new" access described in the blog. A check is not possible without the exact license numbers and without your specific SAP sales contact.
Got it now. But it doesn't make a huge diffenerence whether I buy 75k SAP GW requests or a system user license (each around €400 / year if I remember correctly, but I may be wrong).
Regarding my customer: I will not discuss license topics here on SCN (and yes, we have enough licenses, believe me 😉 ). Thank you though.
HI Uwe,
just used the described solution in a project. It runs out of the box!
Brilliant!
Thanks a lot to You and DJ. I owe you both at least a beer next time we see us.
Regards
Renald
My answer fresh out of the press: #sitHH : Exposing data to #UI5 without using SAP Gateway, Part II: back to standard