Skip to Content

Android and RESTFul web service instead of SOAP

REST instead of SOAP


SOAP at the moment is still the leading standard as it comes to web services. Only with mobile applications the usage and consumption of wsdl files take a lot of overhead. The wsdl files will get big and complex when services are getting bigger proportions. The usage of SOAP is not a standard feature in the android environment. I would like to keep the mobile application as small and standard as possible.

I wanted to connect a standard function module to android and not using SOAP? And that’s when I found a blog titled Real Web Services with REST and ICF by Dj Adams. With a quick and clear solution how to call web services via ICF. And the best thing about it  is that it uses http and nothing else.  Which of course is standard available in the android environment.

For this example I used a standard function module called DATE_GET_WEEK which will give the according week for the supplied date.


Making the function module available as a REST enabled web service.

For making the function module available as a web service I used the ICF framework. You can create a new service by transaction SICF and adding a new sub-element. You have to define a handler element which will take care of the request. In my case I called it Z_CL_DATE_GET_WEEK.

image

Next step is creating the handler class which has to implement the interface IF_HTTP_EXTENSION. This will make the following method available in your class IF_HTTP_EXTENSION~HANDLE_REQUEST. To understand how to implement the method HANDLE_REQUEST. A brief explanation on how the URL handling works     The URL I will be using to call the service will be similar to this. http://system:8000/sap/zrest/week_by_date/20101208.

This can be divided in:
Server and portnumber:  system:8000

Namespace: sap
Service: zrest
Parameters to service:  week_by_date, 20101208

In my example see code below. I ‘ll only be using the second parameter as a date string. By using the date string as the exporting param you can call the function module in reply you will get a week number back including the year. I’m not interested in the year so I will only return the week with the service. It’s an option to also put some error handling in the service.

Implementation of method HANDLE_REQUEST:


method IF_HTTP_EXTENSION~HANDLE_request.
*  [DATA DEFINITION]
DATA:
     path_info     TYPE string,
     verb          TYPE string,
     w_action      TYPE string,
     w_attr        TYPE string,
     w_body        TYPE string,
     gv_date       TYPE datum,
     gv_week       TYPE kweek.
*  [INTERPRET REQUEST]
   path_info = server->request->get_header_field( name = '~path_info' ).
  verb = server->request->get_header_field( name = '~request_method' ).
*  (CHECK METHOD)
* Check if method is get.
   IF verb NE 'GET'.
     CALL METHOD server->response->set_header_field(
       name = 'Allow'       value = 'GET' ).
      CALL METHOD server->response->set_status(       code = '405'       reason = 'Method not allowed' ).
     EXIT.
   ENDIF.
     SHIFT path_info LEFT BY 1 PLACES.
     SPLIT path_info AT '/' INTO w_action w_attr.
*  (RETRIEVE DATA)
* Try to retrieve the week by input date.
   gv_date = w_attr.
    CALL FUNCTION 'DATE_GET_WEEK'
     EXPORTING
       date         = gv_date
     IMPORTING
       week         = gv_week
     EXCEPTIONS
       date_invalid = 1
       OTHERS       = 2.  
*  (NO VALID DATE OR OTHER ERROR OCCORRED)
* Abort with 404 if error
    IF sy-subrc ne 0.
      CALL METHOD server->response->set_status(
       code = '404'
       reason = 'ERROR' ).
      CONCATENATE ''  ''  ''  ''  ''  'h1. ERROR with input param:  '  w_attr  ' '  ''  ''  INTO w_body. 
     CALL METHOD server->response->set_cdata( data = w_body ).   
          EXIT.
     ENDIF.
*  (STORE ATTRIBUTE)
   w_body = gv_week+4(2). "We only need the last to characters for displaying the correct week.
*  (SET CONTENT TYPE)
* Return attribute value in response body
   CALL METHOD server->response->set_header_field(
     name = 'Content-Type'
     value = 'text/plain; charset=utf-8' ).
*  (PUT DATA IN RESPONSE BODY)
   CALL METHOD server->response->set_cdata( data = w_body ).
endmethod.                    "IF_HTTP_EXTENSION~HANDLE_REQUEST

This wraps up the back-end bit. But before using the service in android you can test the service in the browser by calling the URL. The result will look like this.

image

Note: Because I didn’t change the default service settings you’ll be prompted with a logon screen.

Android App

I developed the Android app in Eclipse. For more information on How to develop an android app click here. I’ll only explain how to call the web service in the android environment. You can call the web service via the org.apache.http.impl.client.DefaultHttpClient class which is standard provided in Android and actually is from the HTTP Components project of The Apache Software foundation. Because the service is using Basic Authentication it’s necessary to provide username and password to the DefaultHttpClient. The only problem is this is not by default supported in the HTTP Components project and is only available in the latest beta version. So for a quicker development I used this beta version. It’s also an option to change the authentication settings of the service.

Implementation of the RESTService call





private String callRESTservice(String date) {
    String result = "";
    HttpHost targetHost = new HttpHost("saperp.ciberlabs.local", 8000, "http");
    DefaultHttpClient httpclient = new DefaultHttpClient();
    httpclient.getCredentialsProvider().setCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(_username, _password));
    // Create AuthCache instance
    AuthCache authCache = new BasicAuthCache();
    // Generate BASIC scheme object and add it to the local auth cache
    BasicScheme basicAuth = new BasicScheme();
    authCache.put(targetHost, basicAuth);
    // Add AuthCache to the execution context
    BasicHttpContext localcontext = new BasicHttpContext();
    localcontext.setAttribute(ClientContext.AUTH_SCHEME_PREF, authCache);
    HttpGet request = new HttpGet("/sap/zrest/test/" + date);
    ResponseHandler<String> handler = new BasicResponseHandler();
    try {



result = httpclient.execute(targetHost, request, handler);
    } catch (ClientProtocolException e) {



e.printStackTrace();

result = "ClientException. The input was: " + date;
    } catch (IOException e) {



e.printStackTrace();

result = "IOException. The input was: " + date;
    }
    httpclient.getConnectionManager().shutdown();
    return result;



}

The DefaultHttpClient you provide the URL and the user credentials. After calling the execute function the week number will be returned.
When the application is called and you will click a button to execute the service. The following result will be displayed.

   

11 Comments
You must be Logged on to comment or reply to a post.
    • Hi DJ

      Thanks for the heads-up. It looks very good.
      This will provide a good handle for expanding the approach of using Android SAP connectivity.

      And changing it in a more Business relevant App then just calling a service.

      Kind regards,

      Michael

  • It seems to be useful!

    By the way I try the suggested blog using the same code in my Eclipse framework with the Android SDK.

    But when I run the code emulator gives me the IOException exception. That’s curious because if I test the same url on the emulator’s browser I can connect successfully!

    Any idea?

    Regards.

    • Hi Alejandro,

      The only thing I had done to the emulator. Is changing the Host file. Because i was running my SAP environment in a VM.

      But when i didn’t change the host file i also couldn’t call the URL. So you are properly not having this problem.

      I think it is a problem with one of the library’s which need to be used.
      Maybe debugging the app will give some answers.

      Regards,

      Michael

      • Hi Michael,

        I solve this issue by modifying AndroidManifest.xml file.

        The permission I needed to add was android.permission.INTERNET under “uses-permission”.

        Thank you very much!

        Regards,

        Alejandro

  • Hi Michael,

    Very intersting blog.without using any middlewaredeveloped mobile app.

    As per your blog how to connect backend to mobile if there any connection is created or any other Add-on added to backend business suite.Can you please explain it Architecture of this App?

    Thanks,

    Syam.

    • Hi Syam,

      No special connection is created or add on used.

      By creating the ICF service a direct HTTP connection is available you can also test this in the browser.

      Kind regards,

      Michael

  • Hi Michael,

    It is really nice blog.

    I am trying to implement this example in my system, but while developing application in android eclipse, “AuthCache authCache = new BasicAuthCache(); ” giving me error like BasicAuthCache does not exist. Could you please let me know how to achieve this.

    Thanks & Regards,

    Chandu