Building a CRUD Application with SAPUI5 and ICF REST/JSON Service – Part 1
Introduction
If you, like me, don’t have a system with the UI Add-on and Netweaver Gateway but still wants to learn SAPUI5, you may find this blog series useful. This blog series explains how to create a simple CRUD application from scratch using SAPUI5 and an ICF Service based on REST and JSON.
Table of Contents
Part 1
Prerequisites
Overview
SAPLink Nuggets and Eclipse Project download
References
SAPUI5
SAPLink
SAPLink plugins (SCN Code Exchange)
CL_TREX_JSON_SERIALIZER bug fixes
Extending SAPUI5 JSON Model
Creating the ICF REST Service
Creating the custom handler class
Creating the ICF node
Retrieving the request method and the parameters passed in the URL
Part 2
Implementing the REST Service
Model and DDIC objects
Implementing the Create method (POST HTTP verb)
Implementing the Read method (HTTP GET verb)
Implementing the Update method (PUT HTTP verb)
Implementing the Delete method (DELETE HTTP verb)
Part 3
Creating the User Interface
Creating the project
Setting up the SAPUI5 bootstrap and required libraries
Creating the view components
Creating the BSPs to deploy the application and the SAPUI5 framework.
Implementing the Controller’s methods
Create
Read
Update
Delete
Find
Prerequisites
- You have installed the SAPUI5 Application Development Tool into your Eclipse
- UI Development Toolkit for HTML5 Version SAPUI5 1.8.4
- SAP NetWeaver ABAP 7.01 Stack Level 7 (oldest version where i’ve tested the application) or later
- SAPLink
- Copy of the class CL_TREX_JSON_SERIALIZER with the necessary bug fixes
Overview
This document shows how to create a simple CRUD application using SAPUI5 and ICF REST/JSON service. The frontend applications will be developed using the SAPUI5 framework by using the SAPUI5 Application Development Tool (Eclipse-based tool). The communication will be based on a REST service built here from scratch in ABAP on top of the ICF (Internet Connection Framework). All responses will be JSON based.The application will maintain a simple contact list that will be persisted in a table with the following structure.
Field | Key | Data Element | Data Type | Length | Description |
MANDT | X | MANDT | CLNT | 3 | Client |
X | AD_SMTPADR | CHAR | 241 | E-Mail Address | |
FIRSTNAME | AD_NAMEFIR | CHAR | 40 | First name | |
LASTNAME | AD_NAMELAS | CHAR | 40 | Last name |
SAPLink Nuggets and Eclipse Project download
All objects developed in the ABAP system except the BSPs are available here for download in a .nugg file. To import the objects into your system you need to have the SAPLink installed with the following plugins:
- DDIC
- SICF Nodes
The SAPUI5 eclipse project is available here for download.
References
SAPUI5
- http://scn.sap.com/community/developer-center/front-end
- Get to Know the UI Development Toolkit for HTML5 (aka SAPUI5)
- How to Build a SAP HTML5 Application Using MVC with the SAPUI5 Application Development Tool
SAPLink
http://code.google.com/p/saplink/
SAPLink plugins (SCN Code Exchange)
https://cw.sdn.sap.com/cw/groups/saplink-plugins
CL_TREX_JSON_SERIALIZER bug fixes
http://scn.sap.com/community/mobile/blog/2012/09/24/serialize-abap-data-into-json-format
Extending SAPUI5 JSON Model
http://scn.sap.com/community/developer-center/front-end/blog/2012/11/20/extending-sapui5-json-model
Creating the ICF REST Service
Creating the custom handler class
The first thing we have to do is to create a custom handler to enable us to handle the REST interface requests. The class must be created inheriting from the interface IF_HTTP_EXTENSION.
Go to SE24 and inform the class name ZCL_SCNBLOG2.
Fill in the description and hit the save button.
Now go to the Interface tab and inform the interface IF_HTTP_EXTENSION.
Now go to the methods tab and double click the method HANDLE_REQUEST.
For testing only, insert the code below in order to check if the service is working properly. Don’t forget to save and activate it.
METHOD if_http_extension~handle_request.
CALL METHOD server->response->set_cdata( data = ‘Service Ok!’ ).
ENDMETHOD.
Let’s create the ICF service now.
Creating the ICF node
Go to transaction SICF and hit the execute button.
Expand “default_host” and “sap” nodes. Right click the “bc” node and select the New Sub-Element option in the context menu.
Fill in the name of the service (zscnblog2).
Fill in the service description, select the Handler List tab and inform the class ZCL_SCNBLOG2, the custom handler class.
Save the changes, go back to the previous screen, scroll it down, select the service zscnblog2, right click it and select the Activate Service option in the context menu.
Now let’s test the service. Right click it and select the Test Service option in the context menu. If the SAP GUI Security popup appear select the option “Always allow”.
Your default browser will open requesting your SAP username and password. Be aware that you have to inform the credentials of the correct client. As a result you should see the text “Service Ok!” in your browser.
Retrieving the request method and the parameters passed in the URL
The first thing that the handle_request method must do is identify what is being requested. To do so, we need to retrieve two basic informations: the request method (HTTP verb) and the parameters passed in the URL. The request method describes the action to be performed. The parameters passed in the URL have the information about the resource where the action should be performed.
METHOD if_http_extension~handle_request.
* Variables
DATA: l_verb TYPE string,
l_path_info TYPE string,
l_resource TYPE string,
l_param_1 TYPE string,
l_param_2 TYPE string.
* Retrieving the request method (POST, GET, PUT, DELETE)
l_verb = server->request->get_header_field( name = ‘~request_method’ ).
* Retrieving the parameters passed in the URL
l_path_info = server->request->get_header_field( name = ‘~path_info’ ).
SHIFT l_path_info LEFT BY 1 PLACES.
SPLIT l_path_info AT ‘/’ INTO l_resource
l_param_1
l_param_2.
* Only methods GET, POST, PUT, DELETE are allowed
IF ( l_verb NE ‘GET’ ) AND ( l_verb NE ‘POST’ ) AND
( l_verb NE ‘PUT’ ) AND ( l_verb NE ‘DELETE’ ).
” For any other method the service should return the error code 405
CALL METHOD server->response->set_status( code = ‘405’
reason = ‘Method not allowed’ ).
CALL METHOD server->response->set_header_field( name = ‘Allow’
value = ‘POST, GET, PUT, DELETE’ ).
EXIT.
ENDIF.
CASE l_verb.
WHEN ‘POST’. ” C (Create)
“TODO: call method CREATE of the model
WHEN ‘GET’. ” R (Read)
“TODO: call method GET of the model
WHEN ‘PUT’. ” U (Update)
“TODO: call method UPDATE of the model
WHEN ‘DELETE’. ” D (Delete)
“TODO: call method DELETE of the model
ENDCASE.
“For testing only
CALL METHOD server->response->set_cdata( data = l_verb ).
ENDMETHOD.
To test the service we need a REST client. Here we will use the chrome extension POSTMAN.
The service must accept GET, POST, PUT and DELETE and return the error code 405 for any other method. Let’s check it out.
Before executing our tests it is necessary to fill in the basic auth and refresh the headers.
GET
POST
PUT
DELETE
For any other HTTP verb the expected response is the return error code 405 with the message “Method Not Allowed”. Let’s try PATCH.
PATCH
In the Part 2 we will see the implementation of the Create, Read, Update, Delete methods.
Nice idea and very good blog!
I am also playing around with SAP UI5 at the moment but I am struggling with the tools (I cannot republish my app, always have to remove it and add it afterwards) and with CORS. The usage of the SImpleProxy with 'proxy/http/....' does not work as my local server says it is only allowed to use for local usage !?
So I wonder if you also test your app locally or if it runs only when deployed to the ABAP server?
Hi Mark,
What I do is to test the application as much as possible locally. I use a XAMPP server with a local copy of the SAPUI5. To simulate the responses of the REST interface I like to use static data (.JSON files) with dummy data. I also like to use relative paths, so when I decide to deploy the application the effort of changing the paths is low, specially when is possible to use a similar folder structure.
Thanks for the feedback.
Regards,
Christian
Hi Mark,
You can get around the cross origin issues by inserting this into the http handler ...
server->response->set_header_field( name = 'Access-Control-Allow-Origin' value = '*' ).
This setting really opens up your server however. Wouldn't recommend this for a production implementation. Instead you can be more restrictive by specifying the domain of your server hosting UI5 resources, instead of simply using the '*'.
Regards
John
Thank you for the hint, John.
While this will work for my own datasources I am also looking for a solution to consume example datasources like the Gateway Demo ervices or the public Twitter Stream etc.
While it worked to use a SimpleProxy in a hands-on session at TechEd I can't get this to work on my own laptop.
EDIT: I think the SimpleProxyServlet works now. I had to change my local NW Cloud Webserver to run on Port 80 because my consumed Webservice also runs on Port 80.
Hi Mark,
Yes, a key learning is the port number is included in whether the browser determines that there is a cross-origin situation.
Some other approaches I have also used ...
- If only testing for development purposes on my own laptop, I use Charles Proxy (http://www.charlesproxy.com/) to rewrite the URLs so that my browser thinks it is talking to the same origin. Of course, this is only viable during development, not for a deployed solution.
- It is also possible in some browsers to disable the cross-origin check locally (example http://superuser.com/questions/384871/overriding-access-control-allow-origin-restriction-in-google-chrome), although I have had difficulties getting this working, and in any case I prefer using Charles Proxy because this fixes the problem for all my browsers simultaneously. Of course, this is only viable during development, not for a deployed solution.
- If your scenario needs to work on more than just your laptop, I have used a php proxy solution running from the site that serves my web resources. An example of how this is done is here ... http://codeglobe.blogspot.com.au/2009/05/php-proxy-example-for-yahoo-web.html. Basically, the proxy makes the call directly to the REST API, and passes on the payload to your browser. Since the browser receives the data from the same domain as your web resources, there is no cross-origin conflict.
Regards
John
Good post! I think, it's important to know for every developer, that SAP Netweaver Gateway is not the only option to create REST-based services. Especially when you want to work with SAPUI5.
Hi Michael, thanks for your feedback. One of the main objectives was exactly to show that SAPUI5 is not tied to any server side technology.
Best regards,
Christian
hi man. Its an awesome tutorial. However when am clicking on any button, am having the error "Access Denied". Is there by any chance you know how to solve that problem ?
Hi Shabir,
Thanks for the feedback. You are receiving this error message from which server? Could you please provide more information about the error (a screenshot of the debugger for example).
Thanks,
Christian
Hello Christian,
Sorry for the delayed reply. However the problem came from security exception that we had with the project. The Security team manage to solve it.
Thanks again for your reply and support.
Regards
Shabir Ismail
Hi Christian,
It was an excellent blog, can you please let me know if application developed without using netweaver but UI5 like you did can be used on mobile.?
Thanks
Rahul
Hi Rahul,
Thanks for your feedback.
Yes, it can be used on mobile devices, but there is an entire set of UI5 controls designed for mobile devices.
Supported devices
SAPUI5 SDK - Demo Kit
Demo Apps
SAPUI5 SDK - Demo Kit
Regards,
Christian
Hi Christian,
Thanks for your reply, sorry I did not get your poing you mean to say we will have develope to application one for mobile and other for desktop.
Can you please help me as Fiori works on both the platforms without any problem.
thanks
Rahul
Hi Rahul,
Although they work on both platforms the user interaction is different on mobile devices and desktop applications. In my humble opinion, if you want to get the most of each platform I think it is better to have one app for mobile devices and another for desktop.
Regards,
Christian
Great Christian! As always, exceeding expectations, excellent blog.
Regards,
Nei
Hey Nei, it is nice to see you here on SCN 🙂
Thanks for your feedback.
Regards,
Christian
Hi Christian,
It's very good and helpful blog. if you don't mind I would like you opinion regarding my situation.
In the first statement you have said
"If you, like me, don’t have a system with the UI Add-on and Netweaver Gateway"
In my environment, We have ECC 6.0 EHP6 and equipped with UI Add-On and Gateway Server. My question is our developers are insisting to use this way (Rest/JSON) and even using NW 7.31 Java as the front-end of UI5 (we have it already).
Do you think, it will be similar solution in term of performance, speed of development, configuration efforts, problem solving and required tools (as they use Maven and other products) to use Rest/JSON comparing with UI Add-on & NW Gateway or even this is a better way?
Thanks a lot and really appreciate if you can share some thought.
Best Regards,
Achmad
Hi Achmad,
I'm glad you liked it. Thanks for your feedback.
Well, my opinion is that most people think that the UI Add-On and Netweaver Gateway (and the OData protocol) are prerequisites for UI5 development when actually they are not. There are many other ways to develop and deploy UI5 applications and deciding which way is the best is not an easy task since it involves a lot of things, including personal preferences.
If your developers team already have a set of tools that they are more familiar with, and they can assure you that is possible to achieve the same results, why don´t give them a try?
Best regards,
Christian
Hi Christian,
Actually I have given them the opportunity and we are already in UAT mode. But I found out two important things which could be the major concerns.
The application they tried to built is supposed to be stateful with locking records mechanism. I have raised a while back when they decided to use SAPUI5 (a year ago) and tried to convincing them to stick with Webdynpro with FPM.
I read with NW Gateway, we can use OData feature to do the locking mechanism. And based on SAP Friori architecture design, I got the feeling the only way to get stateful and proper locking mechanism is through Netweaver Gateway.
I think without NW Gateway, the SAPUI5 application just stateless and can't be becoming proper transactional application.
Do you think my understanding is valid argumen?
Thanks a lot,
Best Regards,
Achmad
Hi Achmad,
Actually you can define if your apllication is stateless or statefull inside the ICF Handler, like shown in the example below.
Stateless/Stateful Communication (SAP Library - Components of SAP Communication Technology)
So you don't need NW Gateway to run statefull applications.
Best regards,
Christian
Hi Christian,
Can i send the serialized JSON(json) to cross domain service URL(http:localhost:8045/new/data) using POST method.
"For testing only
CALL METHOD server->response->set_cdata( data = json ).
ENDMETHOD.
Thanks in advance.
Regards,
Sid
Hi Siddesh,
Sorry but I'm not sure that I understood your question. Please take a look at this blog post to see if that is the information you are looking for:
http://scn.sap.com/community/developer-center/front-end/blog/2013/06/29/solving-same-origin-policy-issue-in-different-ways
Regards,
Christian
Hi Chrisitian,
Sorry for late reply. The link which you have mention above will allow to access cross domain but my query is to send the generated JSON to SQL DB.
Eg:
* Serialize ABAP data to JSON
CALL METHOD lo_json_serializer->serialize.
* Get JSON string
CALL METHOD lo_json_serializer->get_data
RECEIVING
rval = lv_json.
* Sets the content type of the response
CALL METHOD server->response->set_header_field( name = 'Content-Type'
value = 'application/json; charset=iso-8859-1' ).
SERVER->response->set_header_field(
EXPORTING
name = 'Access-Control-Allow-Origin'
value = '*'
).
Below is not correct format but i want send the JSON to the URL.
* Returns the results in JSON format
CALL METHOD server->response( data = lvjson
uri = 'http:localhost:8080/new/data' ).
Note: I want to send the JSON (lv_json) to cross domain service URL(http:localhost:8080/new/data) using post method.
Regards,
Sid
Hi Siddesh,
Sorry, but I think you misunderstood the server->response object. The server->response object is the response that will be sent back to the browser (or other client app) that is calling the REST service. If you want to send the JSON to another server you have to fire a HTTP call (POST, GET, ...) from your server, that will act like a client consuming a service of your SQL DB server.
Regards,
Christian
Hi Christain,
You got my query but i am not getting any example to try. Can you please provide sample code or example.
Regards,
Sid
Hi Siddesh,
I think the link below has the information you are looking for
Example Program: Executing an HTTP Request - Components of SAP Communication Technology - SAP Library
Hi Christian,
Thanks...but i am getting error like ICM_HTTP_CONNECTION_FAILED. I need to configure anything.
<tr><td>Detail:</td><td>Connection request from (30/178/0) to host: hostname, service: 8001 failed (NIEHOST_UNKNOWN) AP-T30, U178, 300 XIAFUSER, , 14:22:56, M0, W0, , 1/0</td></tr> </table>
url = 'http:..../data/db'.
call method cl_http_client=>create_by_url
exporting
url = url
importing client = client
exceptions
argument_not_found = 1
internal_error = 2
plugin_not_active = 3
others = 4.
* set http method GET
call method client->request->set_method( 'POST').
*send json which is genearted
call method client->request->set_cdata( data = lv_json ).
* Send
call method client->send
exporting timeout = timeout
exceptions http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
others = 4.
if sy-subrc <> 0.
call method client->get_last_error
importing code = lv_status
message = errortext.
write: / 'communication_error( send )',
/ 'code: ', subrc, 'message: ', dummy.
exit.
endif.
* receive
call method client->receive
exceptions http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
others = 4.
if sy-subrc <> 0.
call method client->get_last_error
importing code = lv_status
message = errortext.
write: / 'communication_error( receive )',
/ 'code: ', subrc, 'message: ', dummy.
exit.
endif.
* close
call method client->close
exceptions http_invalid_state = 1
others = 2.
Regards,
Sid
Hi Siddesh,
Sorry, but you have to ask the basis team to help you on that.
Regards,
Christian
Thank you very much:)
Regards,
Sid
Dear Chirstian,
Thanks a lot for sharing this great post.
I have created an ICF service followed by your guidence. But when I try to access it via the browser like IE or chrome, I always have to input the user and password to get the result.
I have tried to maintain the my user / password for the sap system in the ICF service log on data tab. But still the popup of authorization check comes out.
Do you kindly know how to avoid the authentication step for the sap netweaver server when we call this ICF service?
Thanks a lot and best regards,
Sophie
Hi Sophie,
Thanks for your feedback!
What you did is correct but maybe you forgot to maintain also the service of the BSP created to host the SAPUI5 library.
Best regards,
Christian