Skip to Content

This  blog is about Integration Gateway in SAP Mobile Platform 3.0 (SMP).

In the previous tutorials, we’ve learned how to deal with REST services as data source for an OData service in SMP.

These tutorials were based on the QUERY operation.

Now, since SMP SP06, the READ operation is supported as well.

This blog explains how to do the required steps.

This blog is a follow-up of the tutorial for the QUERY operation, so I’ll skip some of the basic explanations.

Why is this blog necessary?

For the READ operation, you have to know about 2 specialties:

  • How to define the relative URL in Eclipse
  • How to write the script to meet the expected structure of the response.

Please find attached the source files used in this tutorial.

Prerequisites

I expect that you’ve gone through my previous tutorial, explaining REST data source – QUERY operation – XML payload

Prerequisites are the same:

  • Eclipse with SAP Mobile Platform Tools installed
  • SMP SP06
  • Basic knowledge about OData provisioning using the Integration Gateway component of SMP

Preparation

REST Service

For this tutorial, we’ll be using the following REST service as example  service for the data source:

http://www.thomas-bayer.com/sqlrest/CUSTOMER

Please find some info at http://www.thomas-bayer.com

The service is free and doesn’t require any registration.

The reason for choosing this service is that it supports READ of single entries.

The URL for reading a single entry is e.g.

http://www.thomas-bayer.com/sqlrest/CUSTOMER/1

where the 1 is the identifier of a customer entry

Destination

In your SMP server, create a  Destination that points to this REST service.

Please refer to the screenshot for the settings:

After saving the destination, try the Test Connection button: it should be successful.

If you get an error message on connection test, you might consider the following:

Note that you might need to enter proxy settings in your SMP:

https://localhost:8083/Admin/ -> Settings-> System

Note that you might need to restart the SMP server after changing the proxy settings.

OData Model

Create Project

Create project of type SAP Mobile Platform OData Implementation Project.

Define OData Model

Within the OData Modeler, create one EntityType that looks as follows:

Bind data source

Select the odatasrv file and from the context menu choose “Set Data Source”.

In the wizard, you have to first select the Data Source as REST and then select the “Read” operation for the EntitySet “Customers”

Note that the “Read” option is only available since SMP SP 06

Click Next and specify the following relative URL and press “Finish”.

/sqlrest/CUSTOMER/{ID}

How are we supposed to build this relative URL?

Here we have to understand:

As we already know, any REST service is free to use its own patterns for providing resources.

Since no READ operation is explicitly specified for REST services (like for OData), any REST service out there in the internet can implement it in its own preferred way.

Which means that our SMP server cannot deduct the URI to find a single entry, only from the service URL (of the REST service)

So it’s us who have to provide the information (about how the REST service does the READ) to the SMP server.

Let’s have a look at our example REST service.

How is the READ implemented there:

http://www.thomas-bayer.com/sqlrest/CUSTOMER/1

There’s the segment “CUSTOMER” which provides the list of entries

Afterwards a slash

Finally a number which is the value of the property “ID” of the thomas-bayer service

Translated into a generic expression:

CUSTOMER/<value-of-ID-field>

(value-of-ID-field means the 1 or 2 or 42 that we can enter at the end of the thomas-bayer URL)

And this is what SMP expects from us:

A generic expression that provides the key property between curly braces

So we have to provide the full URI of the READ, but with a variable instead of the concrete value

But the “full URI” has to be a “relative URL”, because it is concatenated with the base URL that is defined in the Destination on the server.

Custom Code

After finishing the binding wizard, we’re ready to create the script.

Within the Project Explorer View, select the “Read” node and choose Define Custom Code from the context menu.

Choose Groovy as language.

Now we have to implement the processResponseData() method.

What do we have to do?

Background

The REST service that we’re using supports reading of a single entry.

The URL

http://www.thomas-bayer.com/sqlrest/CUSTOMER/1

returns the following response:

Note that the browser doesn’t display the real full payload (the xml header is hidden), so we have to press “view source” to get the real response payload:

In our custom code script, we’re supposed to provide the data in a specific structure, as we’ve learned in the previous tutorials.

In the case of READ, the expected structure looks as follows:

<EntitySet>

    <Entity>

          <Property1>“value of property1”</Property1>

          <Property2>“value of property2”</Property2>

          <Property3>“value of property3”</Property3>

    </Entity>

</EntitySet>

As you can see, the structure is the same like in the QUERY scenario.

Note that for reasons of consistency, the structure contains the EntitySet, although the payload of the READ operation doesn’t contain it.

In our custom code script, we have to modify the structure of the REST response to match the structure that is expected by the SMP server.

Intermediate step

For those of you who like to do an intermediate step: before we start to generically modify the response of the REST service in order to meet the expected structure, we can provide a hard-coded response (as we did in the first REST tutorial).

Such implementation looks as follows:

def Message processResponseData(message) {

  

   message.setBody(“<Customers>”+

                                         “<Customer>”+

                                               “<ID>111</ID>”+

                                               “<FIRSTNAME>Jack</FIRSTNAME>”+

                                         “</Customer>”+

                                  “</Customers>”);

          

   return message;

}

After generate, deploy, configure and run the service, you should see the result in the browser.

Check the section below for info about how to run the service.

Note:

In this hard-coded response, we’re setting less properties than defined in our OData model. But this is OK, at runtime the remaining properties will be empty.

Remember: Our OData model can be bigger than the REST-service, but it must not be smaller (which would cause exceptions at runtime).

Implement the script

Now let’s do the generic implementation:

Modify the structure of the REST response to match the structure that is expected by SMP.

Fortunately, in our example the REST service payload is very similar to the expected structure.

In detail, what we have to do, is the following:

  • Remove undesired xml header:
    <?xml version=”1.0″?>
  • Remove undesired attributes of the entry tag
    <CUSTOMER xmlns:xlink=”http://www.w3.org/1999/xlink“>
  • Rename the entry name to match our EntityType name
    </Customer>
  • Surround the entry with opening and closing tags of our EntitySet name
    <Customers>
  • Add the opening Customer tag
    <Customer>


This is the simple implementation of the method:

def Message processResponseData(message) {  

    String restResponse = message.getBody();

  

       int index = restResponse.indexOf(“xlink\”>”)  + 7;

    restResponse = restResponse.substring(index);

    restResponse = restResponse.replaceAll(“</CUSTOMER>”, “</Customer>”);

    restResponse = “<Customers><Customer>” + restResponse + “</Customers>” ;

    message.setBody(restResponse);

  

       return message;

}

Result

After doing generate&deploy in our Eclipse project, change to your browser and open the Management Cockpit.

Assign the destination that we’ve created in the preparation step.

Invoke our OData service.

Note that we haven’t implemented the QUERY, so we have to directly invoke a URL for READ of a single entry:

e.g.

https://localhost:8083/gateway/odata/SAP/<your_service_name>/Customers(’42’)

The result is:

Summary

There should be 2 basic learnings from this tutorial:

  • How to provide the relative URL when specifying the REST data source
  • How to write the custom code to meet the expected structure for READ operation in Integration Gateway

Those of you who have followed my blog explaining how to use xml parser for creating the expected structure may ask: Is there a follow-up blog explaining how to do this for the READ operation?

Well, I’m not intending to create such a blog, since the procedure is exactly the same.

Links

The prerequisite tutorial that does the same like this blog, but for QUERY operation:

Introduction in REST data source part 3: Understanding the return structure in xml

http://scn.sap.com/community/developer-center/mobility-platform/blog/2015/02/12/integration-gateway-understanding-rest-data-source-3-query–xml-standard

Preparing Eclipse for Groovy scripting: http://scn.sap.com/docs/DOC-61719

Introduction in REST datasource part 1: Understanding the return structure in xml

http://scn.sap.com/community/developer-center/mobility-platform/blog/2015/02/10/understanding-rest-data-source-in-integration-gateway-1-query-very-simplified

Introduction in REST data source part 2: Understanding the return structure in json

http://scn.sap.com/community/developer-center/mobility-platform/blog/2015/02/11/integration-gateway-understanding-rest-data-source-2-query–json-very-simplified

Installing SMP Toolkit:

http://scn.sap.com/community/developer-center/mobility-platform/blog/2014/08/22/how-to-install-sap-mobile-platform-tools-for-integration-gateway-in-eclipse-kepler

Tutorial for OData provisioning in SMP:

http://scn.sap.com/community/developer-center/mobility-platform/blog/2014/06/10/creating-an-odata-service-based-on-sap-gateway-soap-jdbc-and-jpa-data-sources-ba

To report this post you need to login first.

9 Comments

You must be Logged on to comment or reply to a post.

  1. Martin Kraemer

    Hi Carlos,

    thanks for all your detailed tutorials. I followed your guide but I continue to receive the following error.

    Exchange[

    Id ID-v10393-54688-1426679425095-11-7

    ExchangePattern     InOnly

    Headers {breadcrumbid=ID-v10393-54688-1426679425095-11-6, CamelRedelivered=false, CamelRedeliveryCounter=0, contenttype=application/xml;charset=utf-8, DestinationName=THOMASSERVERREST, functionname=processRequestData, odatacontext=org.apache.olingo.odata2.core.ODataContextImpl@38c52ed2, odatamethod=GET_ENTRY, relativeuri=/sqlrest/CUSTOMER/42, scriptfile=Customers_REST_Read.groovy, scriptfiletype=groovy, uriinfo=com.sap.gateway.core.ip.odata.OGWUriInfo@1984fa1c}

    BodyType null

    Body [Body is null]

    ]


    Confusingly this relates to processRequestData which is never used within your tutorial.


    Any idea?


    br

    Martin

    (0) 
    1. Carlos Roggan Post author

      Hi Martin,

      thanks for following my tutorials, I’m glad that they’re used;-)

      From the snippet, I cannot see what error is actually logged.

      It seems that the processResponse is not invoked, because the service-roundtrip is interrupted while calling the backend REST service

      I’ve checked the full URL

      http://www.thomas-bayer.com/sqlrest/CUSTOMER/42

      And it is valid.

      So what else could be the case?

      Is your destination valid?

      Have you maybe coincidentally deleted the message object in the processRequestData method…?

      I mean the line

      return  message;

      Cheers,

      Carlos

      (0) 
      1. Martin Kraemer

        Hi Carlos, thanks for your response. the destination is valid and I didn’t delete anything in the processRequestData method.

        This is my Customers_REST_Read.groovy

        import com.sap.gateway.ip.core.customdev.util.Message;

        /**

        Function processRequestData will be called before the request uri is

        handed over to the REST service. User can manipulate the request uri here.

        */

        def Message processRequestData(message) {

          //You can modify the RelativeUri Header for custom requirements

          return message;

        }

        /**

        Function processResponseData will be called after the response data is received

        from the REST service. User can manipulate the response data here.

        */

        def Message processResponseData(message) {

          String restResponse = message.getBody();

          int index = restResponse.indexOf(“xlink\”>”)  + 7;

          restResponse = restResponse.substring(index);

          restResponse = restResponse.replaceAll(“</CUSTOMER>”, “</Customer>”);

          restResponse = “<Customers><Customer>” + restResponse + “</Customers>” ;

          message.setBody(restResponse);

          return message;

        }

        (0) 
        1. Carlos Roggan Post author

          Hi Martin,

          I’ve tried the tutorial again and it works for me.

          It even works with your code snippet.

          Now I’ve tried the following:

          In my processRequest method, I’ve done

          return null;

          This leads to an error and I get the Exchange-entry in the log.

          In my case, it looks slighty different.
          E.g. I don’t have the  header “DestinationName” and also a header name is different.

          So maybe the reason is that you have a different/wrong SMP-server-version?

          Kind Regards,

          Carlos

          (0) 
  2. Martin Kraemer

    Hi Carlos, the server was in some kind of error state. I’ve reinstalled another sandbox server and it seems to be working right now. I’ll find a solution for the other server… br martin

    (0) 
    1. Carlos Roggan Post author

      Hi Vishnu,

      I understand your confusion 😕 and you’re right to ask;-)

      You’re again right, actually, you have to tell exactly this to the FWK, because it could never know.

      You tell it already in Designtime, in Eclipse, when you do the binding.

      You declare that

      /sqlrest/CUSTOMER/{ID}

      means

      /Customers(’42’)

      Cheers,

      Carlos

      (0) 

Leave a Reply