Skip to Content
Author's profile photo Ivo Kulms

PI REST Adapter . Exposing a function module as RESTful service

This blog is part of a collection of blog entries that shows architectural concepts and configuration of the SAP PI REST Adapter. We also added some sample scenarios to make it easier for you to understand how your scenario can be implemented using the PI REST Adapter.

If you haven’t done so far, best is to start with the very first blog PI Rest Adapter – Don’t be afraid within the blog series covering the concepts of the REST adapter. A complete list of all blog entries can be accessed from here PI REST Adapter – Blog Overview.

The current blog describes how to call a function module via PI’s RFC adapter, and expose the same as a RESTful service.

Scenario

We would like to read customer data from an ERP backend system calling a remote function module, and expose this interface as RESTful service. The customer ID is passed to the service as part of the URL of the RESTful service call. In order to map the customer ID to the corresponding input field of the function module, we need to retrieve the ID from the URL, and store the same as adapter specific attribute.

In the SAP Process Integration Designer perspective of the NetWeaver Developer Studio (NWDS), I have defined an Integration Flow with a REST sender channel and an RFC receiver adapter. In the operation mapping, the value of the adapter specific attribute is read, and mapped to the function module structure.

01 Integration Flow.png

Configuring the REST sender channel

On the Integration Flow, double click on the sender channel, and switch to tab General below the Adapter-Specific settings. In our specific case, the settings for the input message format, i.e., the format of the request message are superfluous since we do not provide any payload anyway. As mentioned above, the required customer ID is part of the URL. Choose Quality of Service Best Effort. The format of the output message, i.e., the response, should be JSON. Within PI, the format of the response from the remote function call is XML, so we need to select the Convert XML Payload to JSON check box.

02 General.png

We would like to define a custom end point. On the Channel Selection tab we specify the static part of the end point URL whereas on the REST Resources tab we define the dynamic part that will hold the customer ID. Switch to tab Channel Selection, and select the Specify Endpoint check box. As endpoint, we enter /demo/query/customer. Furthermore, we can limit the endpoint to specific http operations. We would like to allow the service being called via the GET http operation only, so we select the Limit to HTTP Operation check box, and the GET http operation from the drop down box.

03 Channel selection.png

Switch to tab REST Resources, and define the URL pattern as /{id_part}. The pattern element id_part is a placeholder for the customer ID. As mentioned above, we need to store the customer ID within a dynamic attribute. In the XI Dynamic Attribute section, we map the pattern element id_part to the dynamic attribute id.

04 REST resources.png

Mapping the customer ID

In the ESR, I have created a user defined function getASMA  to read the value of the dynamic attribute:

@LibraryMethod(title=“getASMA”, description=“get adapter specific message attribute”, category=“UDFPool”, type=ExecutionType.SINGLE_VALUE)

      public String getASMA (

            @Argument(title=“”) String namespace,

            @Argument(title=“”) String attribute,

             Container container)  throws StreamTransformationException{

            Map<String, Object> all = container.getInputHeader().getAll();

            DynamicConfiguration dynConf = (DynamicConfiguration)all.get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);

            DynamicConfigurationKey key = DynamicConfigurationKey.create( namespace, attribute);

            String value = dynConf.get(key);

            return value;

      }


As input parameter of the function I pass the key of the attribute, in our case name id with namespace http://sap.com/xi/XI/System/REST. The value of the attribute is mapped to the input field CUSTOMERNO of the function module.


05 Mapping with details.png


Running the scenario

For testing the scenario you can use the Advanced REST Client Application in the Google Chrome browser. The endpoint URL of your RESTful service starts with http://<host>:<port>/RESTAdapter with host and port of the SAP PI system, followed by what you have defined in the sender channel, here /demo/query/customer/<id>.


Example: Assuming we would like to gather information of customer with ID 26, so the URL would be as follows:


http://<host>:<port>/RESTAdapter/demo/query/customer/26

As a response we would get the customer details in JSON format as can be seen in figure below.

06 Chrome browser GET.png

I hope this blog was helpful to understand how to expose a function module as RESTful service using the SAP PI REST adapter. If you like to learn more, check out the other blogs in the series, accessible from the main blog PI REST Adapter – Blog Overview.

Assigned Tags

      15 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi Ivo

      Many thanks for the blog - very useful and informative. I was wondering if you could clarify something for me. I am slightly confused about exactly what values should be used in the table on the "Operation Determination" tab for a Sender Channel, specifically the "variable" column. So far as I understand, it is by using this table that I need to map my REST operation (e.g. GET) to my PI Operation via Operation and namespace. But this table does not have any input help in the UI and I am confused as to which values should go in there? The help doc says:

      Determine XI Operation

      On the Operation Determination tab you specify how REST operations map to XI operations. For the PI system, the incoming message needs to contain information about the operation/message type as an outer XML element of the message content. For each operation pair you need to add a row to the XI Operation table and provide the following information:

      • The REST operation by the Variable holding the information and possible values of this variable as an Expression
      • The XI operation by the message type in PI that is associated with the desired Operation and its Namespace

      So does this mean for example that I have to map "GET" to "MyOperation in urn:MyNamespace"? but if so I am not clear on what the possible values for the "Variable" column should be to achieve this?

      And do we always need a value in this table? I am using a single operation type and single PI Operation but I still get the message: "No matching rule to map interface found".

      Many thanks!

      Chris

      08 Jan 2015, Edit to Add:

      Hi Ivo - apologies, I just found your other blog which answers my above question here - thanks

      Author's profile photo Ivo Kulms
      Ivo Kulms
      Blog Post Author

      Hi Chris,

      thanks for your feedback. I will take your question as a hint that the standard documentation is a bit "weak" on the topic "Operation Determination" and will add some more examples.

      Have a great New Year 2015!

      ivo

      Author's profile photo Adalid Andrés Hernández
      Adalid Andrés Hernández

      Hi Chris,

      Regarding "No matching rule to map interface found" error, please check you ESR objects are correctly set up, I had to update a Message Type on Operation Mapping.

      Regards,

      Adal.

       

       

      Author's profile photo Former Member
      Former Member

      Hi Ivo,


      When we test the scenario to processing messages the adapter reports the error message:


      Error while sending message to module processor: senderChannel '589b39c9b91c3ae99040d9addc6a818b': Catching exception calling messaging system: Unable to parse XML message payload to extract operation for receiver determinationorg.xml.sax.SAXParseException: Premature end of file.


      Anyone an idea or solution direction?

      Thanks in advance.

      Cheers, Luc

      Author's profile photo Ivo Kulms
      Ivo Kulms
      Blog Post Author

      Hi Luc,

      your problem seems similar to the one mentioned above by Christopher.

      Either you use a Dummy Interface in the IFlow for the adapter or you have to specify on the Operation Determination Tab which XI Operation / Interface should be used. The table on the tab allows to specify different interface name depending on the internal variables. In the variable columns add for example the REST operation, by entering "operation", in the expression column "GET" or "POST" or "*" and in the operation/namespace columns the XI operation / interface you want to reference.

      I know this is a tricky part in the configuration of the adapter and the should UI support it in a more easy way...

      Hope this helped,

      ivo

      Author's profile photo Ivo Kulms
      Ivo Kulms
      Blog Post Author

      There was a type in my answer: The variable "operation" has to be in curly brackets, so that it gets evaluated.

      Author's profile photo Former Member
      Former Member

      Ivo... Wonderful blog and very informative.

      I am getting the same error after followed all your steps. Even adding operations too.

      I am using simple Material Details search. REST to ABAP Proxy. My scenario is working fine with SOAP.

      Error while sending message to module processor: senderChannel  Catching exception calling messaging system: Unable to parse XML message payload to extract operation for receiver determinationorg.xml.sax.SAXParseException: Premature end of file.

      Please help!

      Please suggest any documents on REST adapter in PO environment.

      Thanks

      YRv...

      Author's profile photo Ivo Kulms
      Ivo Kulms
      Blog Post Author

      Ooops. In my answer to Luc was a typo...

      The variable "operation" has to be in curly brackets, so that it gets evaluated. So the entry should look like "{operation}" ( or like "{service}" if you want to map the XI operation by REST service name)

      Author's profile photo Former Member
      Former Member

      Hi Ivo,

      What is the value of the constant, I marked with a green & yellow star in the picture below? Could you share customer_query data type structure in your sample? No tailstring function in our system. What should I use instead of tailstring function?

      Thanks

      /wp-content/uploads/2015/02/mapping_647507.png

      Author's profile photo Alexander Bundschuh
      Alexander Bundschuh

      Hi Esra,

      we haven't mentioned those details here since they are not relevant for understanding the REST specific features, the rest of the mapping is rather scenario specific.

      Anyway, I need to ensure that the customer no is a 10 digit number with leading zeros, so I add 10 times 0 to the value, and with tailString I keep only the last 10 digits, so the green constant is "0000000000", the red constant is "10". There might be better ways to achieve this but that'S all taht came to my mind. The tailString function actually comes with the deployment of the b2b add-on, I just nicked it.

      Here we go:

      @LibraryMethod(title="tailString", description="remove leading characters", category="UDFPool", type=ExecutionType.SINGLE_VALUE)

      public String tailString (

      @Argument(title="")  String value,
      @Argument(title="")  String tailLength,
      throws StreamTransformationException{

      null;

      if (value != null && tailLength != null

      int tailLengthInt;

      try {

      catch (NumberFormatException numberFormatExp) {

      throw new RuntimeException(

      "UDF tailString: could not convert tailLength"

      " to integer");

      "";

      int valueLength = value.length();

      for (int i = valueLength; i > 0; i--) {

      if (value.charAt(i - 1) != ' ') {

      break;

      int length = trimmedValue.length();
      if (length > tailLengthInt) {
      else {
      else {
      return output;

      }

      The customer_query data type just has a field id of type string

      that's it

      Alex

      Author's profile photo Former Member
      Former Member

      Hi Alex,

      I am getting an error as you see below. Do you have any suggestion?

      Error while sending message to module processor: senderChannel 'bb592eb66d7f309daf583d93f6e4a370': Catching exception calling messaging system: XIServer:CX_RD_PLSRV::Problem while determining receivers using interface mapping: Error while determining root tag of XML: BOM / charset detection failed::::Error when determining the receiver: Problem while determining receivers using interface mapping: Error while determining root tag of XML: BOM / charset detection failed Problem while determining receivers using interface mapping: Error while determining root tag of XML: BOM / charset detection failed Error while determining root tag of XML: BOM / charset detection failed Error while parsing an XML stream: 'BOM / charset detection failed'.


      Thanks

      Author's profile photo Former Member
      Former Member

      Hello Ivo / Alexander,

      We had a requirement for Exposing the Function module as RESTful service. In that I am using  Synchronous Sender Rest Adapter where I want to give 2 Runtime parameters(TOKEN, INPUTREQUEST) in the URL and the RFC should give the response back.

      The sample Request URL will be like:

      http://Host:Port/RESTAdapter/Demo/PO?TOKEN=12345&INPUTREQUEST=<?xml version="1.0" encoding="UTF-8" ?>

      <Z_Request>

      <REGION>ASIA</REGION>

      <SOURCE_SYSTEM>PRO</SOURCE_SYSTEM>

      <item>

      <KOKRS>1000</KOKRS>

      <BUKRS>100</BUKRS>

      </item>

      </Z_Request>

      The communication channel configuration:

      REST.png

      When we place the URL in Rest Client tool, SAP PI takes the 2 parameters through GET variable but the value of INPUTREQUEST is getting truncated as "<?xml version". We cant able to send the complete xml as input to "INPUTREQUEST".

      Kindly suggest some ideas/solutions for this issue.

      However the call is successful without ‘=’ symbol in the XML Header, please find the URL for the reference.

      URL:

      http://Host:Port/RESTAdapter/Demo/PO?TOKEN=12345&XMLREQUEST=<?xml version="1.0" encoding="UTF-8" ?>

      <Z_Request>

      <REGION>ASIA</REGION>

      <SOURCE_SYSTEM>PRO</SOURCE_SYSTEM>

      </Z_Request>

      Please suggest the potential solution to achive the above business case since we also tried the adapter module to manage the call but somehow the Rest sender adapter is not supporting the same.

      Many Thanks

      Ezhil.

      Author's profile photo Former Member
      Former Member

      Hi,

      How can I achieve this functionality without using NWDS. I mean mapping sender with dynamic attributes.

      please advise.

      Regards,

      Venu

      Author's profile photo Sara Schmidt
      Sara Schmidt

      Hi Gurus,

      maybe I'm too naive to the REST Topic. 😛

      I do not always know how to define the Sender and Receiver Intefaces.

      Who can explain me and give me more Details, such as a step-by-step guide?

      thanks a lot!

      Regards

      Sara

      Author's profile photo Former Member
      Former Member

      Hi Ivo,

      I have a scenario which Integrates

      SAP ECC and SAP UI5 via SAP PI 7.4 server in a bidirectional data flow by means of RFC BAPI-XML conversion synchronously using RFC and REST adapter within internet.

       

      Open PO's are send from SAP ECC to UI5 and gets the acknowledgment back i.e response from UI5 to SAP ECC via SAP PO server.

      Please help on this. Many thanks

      https://answers.sap.com/questions/51166/how-to-integrate-sap-po-server-with-ui5.html?childToView=52401#comment-52401