Skip to Content

SAP oData Service [GET]: Consume REST Service

Overview

  • In this blog, we try to consume a REST-Services in an OData-Service.
  • Here we use GET operation of OData-Service
  • and while consuming the REST-Service, we use HTTP-Method as POST to send request message and in acknowledgement REST-Service provides response which will be mapped to OData-Service’s structure.
  • This blogs is a business case example of parent blog:

Business Scenario:

  • In a fiori-app, where data need to be accessed from a non-sap system.
  • This non-sap system has a REST-Service technique for data exchange to out-side world.
  • So, in fiori-App, we need an oData-Service which can consume/talk to non-sap’s REST-Service for data Exchange.
  • Note: Here we can consume REST-Services directly in fiori-App, but we recommend to access this via oData-Service, due to following reasons:
    • The Cross-domain issue in JavaScript codes while accessing REST-Services when we deploy fiori-App in Fiori-Server.

REST Service Details:

  • This REST-Service of non-sap system is a medium for data exchange between SAP-FioriApp and non-sap system
  • REST (REpresenational State Transfer) is an architectural style that uses simple and lightweight mechanism for inter-machine communication.
  • In this blog’s example, this REST-Service has following components for data-exchange:
    1. EndPoint-URL:
      • This consists of http(s), host, port and RestProjectPath of Non-SAP system
      • For Example:
        • http://<ServiceIP>:<Port>/<REST_Service_Path>
    2. Access-credentials:
      • user-id and password which is required to access this REST service
    3.  Request-Message:
      • This is the input format which respective REST-Service understands, for which it runs its program logic and returns data accordingly.
      • Here, below is the JASON input format:
      • [  
           {  
              "taskId":286079
           },
           {  
              "taskId":287571
           }
        ]
    4. Response-Message:
      • This is the output message format which we receive from REST-Service in acknowledgement.
      • Here, output format is like:
      • {  
           "response":"Success",
           "responseData":{  
              "response":"Posted successfully"
           },
           "error":null,
           "errorList":[]
        }
  • REST Services are working with ‘Resources’ instead of ‘Operations’

Steps to create oData Service [with GET_ENTITYSET]:

  • To Consume above REST-Service, we implement oData-Service in following manner:
    • Creation of an EntitySet which will have two Property:
      • REQUEST
        • To send JSON-Input in given REST-Service format
      • RESPONSE
        • To receive JSON-output from REST-Service.
    • Re-Definition of method ‘GET_ENTITYSET‘ of respective Enity, where we write ABAP-Code to consume REST-Service.
  • Following detailed Steps can be followed for same:

[1] Create an EntityType and EntitySet 

  • To Create an OData-Serivice, go-to SAP-Firoi-Server t-code ‘SEGW’
  • Right click on Project’s folder ‘Entity Types’ to create an Entity
  • with Name ‘ConsumeREST’ with EntitySet name ‘ConsumeRESTSet’
  • Create two properties (REQUEST and RESPONSE) and make REQUEST as key.
  • Save and ‘Generate Runtime object’ by clicking circle icon (red/white)  with project selection.
  • Thus meta-structure for EntitySet gets created.

 

[2] Redefine method ‘ConsumeRESTSet_GET_ENTITYSET

  • Next we need to re-define method ‘GET_ENTITYSET‘ where abap-code will be written to consume REST service. This method will have following functionalities:
    • Get input from property ‘REQUEST’ of ODataService’s EntitySet ‘ConsumeRESTSet’
    • Consume/trigger REST-Service with this input
    • In acknowledgement, REST-Service provide response, extract it and map it to oDataService’s EntitySet ‘ConsumeRESTSet’ in property ‘RESPONSE’
  • To re-define same, go to Odata-Service project’s folder ‘Runtiime Artifacts’ -> select ‘DPC_EXT’ class -> double click on it to go to abap runtime workbench
  • Below is ‘_DPC_EXT’ class, where we re-define ‘GET_ENTITYSET
  • Go to folder ‘_DPC_EXT’ -> folder ‘Methods’ -> folder ‘Inherited Methods’
  • select method ‘ConsumeRESTSet_GET_ENTITYSET‘ -> right click -> select ‘Redefine’
  • Once method redefined, it get listed inside folder ‘Methods/Redefinitions’
  • and we write abap-code iside this method to do following tasks:
    • To read input from property ‘REQUEST’ of ODataService’s EntitySet ‘ConsumeRESTSet’
    • Call REST-Service by sending input and using its endpoint url
    • In acknowledgement, REST-Service provide response,
    • extract it and map it to oDataService’s EntitySet ‘ConsumeRESTSet’ in property ‘RESPONSE’
  • Please note:
    • We can not do it in redefinition of GET_ENTITY,  because get_filter does not accessible inside it.
  • Below is the screen of method ‘ConsumeRESTSet_GET_ENTITYSET
  • And ABAP code written inside method ‘ConsumeRESTSet_GET_ENTITYSET‘ is as follows:
  • method CONSUMERESTSET_GET_ENTITYSET.
    
    DATA: lt_filters            TYPE /iwbep/t_mgw_select_option,
          ls_filter             TYPE /iwbep/s_mgw_select_option,
          ls_so                 TYPE /iwbep/s_cod_select_option,
          LS_CONSUMERESTSET     TYPE ZCL_ZTEST_ODATA_MPC=>TS_CONSUMEREST.
    
    DATA: lv_RestSrvUrl         TYPE STRING,                     "Var for Http REST Service Url
          lv_HTTP_CLIENT        TYPE REF TO IF_HTTP_CLIENT,      "Var for Rest Http Client     
          LV_REQUEST            TYPE STRING,
          LV_RESPONSE           TYPE STRING.
    
    
    * Initiating filter to Read input from EnitySet of ODataService
      lt_filters = io_tech_request_context->get_filter( )->get_filter_select_options( ).
    
    * Extract input from Property 'REQUEST' of EntitySet 'CONSUMERESTSet'
      Clear ls_filter.
      READ TABLE lt_filters WITH TABLE KEY property = 'REQUEST' INTO ls_filter.
      IF sy-subrc EQ 0.
        READ TABLE ls_filter-select_options INTO ls_so index 1.
        IF sy-subrc EQ 0.
          LV_REQUEST = ls_so-low.
        ENDIF.
      ENDIF.
    
    * REST Service URL
    lv_RestSrvUrl = 'http://<ServiceIP>:<Port>/<REST_Service_Path>'.
    
    *Steps to Call REST Service ===================================
    *STEP-1 : CREATE HTTP CLIENT
    CALL METHOD CL_HTTP_CLIENT=>CREATE_BY_URL
        EXPORTING
          URL                = lv_RestSrvUrl
        IMPORTING
          CLIENT             = lv_HTTP_CLIENT
        EXCEPTIONS
          ARGUMENT_NOT_FOUND = 1
          PLUGIN_NOT_ACTIVE  = 2
          INTERNAL_ERROR     = 3
          OTHERS             = 4
          .
    
    *STEP-2 :  AUTHENTICATE HTTP CLIENT
    CALL METHOD LV_HTTP_CLIENT->AUTHENTICATE
      EXPORTING
        USERNAME        = 'Service_user-id'
        PASSWORD        = 'Service_password'.
    
    *STEP-3 : Set headers for REST Service Request Call
    CALL METHOD lv_HTTP_CLIENT->REQUEST->SET_HEADER_FIELD
         EXPORTING NAME  = '~request_method'
                   VALUE = 'POST'.
    
     CALL METHOD lv_HTTP_CLIENT->REQUEST->SET_HEADER_FIELD
          EXPORTING NAME  = 'Content-Type'
                    VALUE = 'application/json; charset=utf-8'.
    
     CALL METHOD lv_HTTP_CLIENT->REQUEST->SET_HEADER_FIELD
          EXPORTING NAME  = 'Accept'
                    VALUE = 'application/json, text/html'.
    
    * STEP-3.1 : Attach Request Message
    CALL METHOD LV_HTTP_CLIENT->REQUEST->SET_CDATA
         EXPORTING DATA   = LV_REQUEST
                   OFFSET = 0.
    
    *STEP-4 :  SEND HTTP REQUEST
      CALL METHOD lv_HTTP_CLIENT->SEND
        EXCEPTIONS
          HTTP_COMMUNICATION_FAILURE = 1
          HTTP_INVALID_STATE         = 2.
    
    *STEP-5 :  GET HTTP RESPONSE
    CALL METHOD lv_HTTP_CLIENT->RECEIVE
          EXCEPTIONS
            HTTP_COMMUNICATION_FAILURE = 1
            HTTP_INVALID_STATE         = 2
            HTTP_PROCESSING_FAILED     = 3.
    
    *STEP-6 :  Extract Rest-Service-Response
    CLEAR LV_RESPONSE.
    LV_RESPONSE = lv_HTTP_CLIENT->response->get_cdata( ).
    
    *STEP-7 : Appending Rest-Service-Response to EntitySet of ODataService
    CLEAR LS_CONSUMERESTSET.
    LS_CONSUMERESTSET-REQUEST  = LV_REQUEST.  "Append Sent Request
    LS_CONSUMERESTSET-RESPONSE = LV_RESPONSE. "Append Receievd Response
    
    APPEND LS_CONSUMERESTSET TO ET_ENTITYSET.
    CLEAR LS_CONSUMERESTSET.
    
      endmethod.
  • Save and activate this method.

 

[3] Testing OData-Service which consumes REST-Service

  • Once above implementation gets completed, we can begin testing of service.
  • Note: before testing make sure, odataService is already registered, for same you can refer below blog of mine:
  • For testing in Fiori-server, go to t-code ‘/n/iwfnd/gw_client’ and below oDataService uri will be used to invoke REST service via oData.
    • here we are referring EntitySet ‘ConsumeRESTSet’
    • and in property ‘REQUEST’ we are passing JSON-Format input string which need to be send to REST-Service while calling
    • This JSON-Input-String is REST-Service’s input message format.
  • /sap/opu/odata/sap/ZTEST_ODATA_SRV/ConsumeRESTSet?$filter=REQUEST eq '[{"taskId":286079},{"taskId":287571}]'
  • select Protocol ‘HTTP’
  • select HTTP Method ‘GET’, here please note we are passing input in uri
  • Execute press ‘F8’ -> and in acknowledgement, we received REST-Service’s output in Property ‘RESPONSE’.
  • for reference Here ‘REQUEST’ property has same data which we supplied as an input.

[4] Debugging OData-Service which consumes REST-Service

  • Lets debug method ‘ConsumeRESTSet_GET_ENTITYSET’ to understand data flow.
  • Set external breakpoints
  • Execute/trigger oData Service from t-code ‘/n/iwfnd/gw_client’
  • Debugger enters in method, see first we have extracted input from property ‘REQUEST’ of ODataService’s EntitySet ‘ConsumeRESTSet’ into variable LV_REQUEST
  • Next debugger stops post calling REST-Service, where we can understand with help of variable data ‘LV_RESPONSE’ which has extracted output from REST-Service acknowledgement
  • The REST-Service’s output present in variable ‘LV_RESPONSE’. is been mapped/populated to oData-Service’ EntitySet ‘ConsumeRESTSet’ with help of structure ‘ET_ENTITYSET’ as shown in below screen
  • Thus we have understood how data is flowing from oDataService call to REST-Service call.

 

2 Comments
You must be Logged on to comment or reply to a post.
  • Hi Dilip,

    Thanks for sharing the information, This blog was really helpful.

    I am trying for the same through post method but whatever the request payload, we are giving is not being taken in er_entity in create_entity method of data provider class and response is 201 but not able to see the output.

    Could you kindly guide me the difference which we have to follow for post method to work as expected.

    Thanks in advance

    Regards

    Ragav

     

    • Hi Ragavendiran,

      Here, in this blog, trick I have used, is like,

      • to post/send some data to REST URL via OData-Service, in OData-Service-URL-pattern itself, passing complete JSON-String-Data into parameter <REQUEST> and calling as a GET Method.
      • Once input JSON-received inside OData-Service’s GetEntitySet Method, passing same input to REST Url as a POST Method.

      Thus, in summary, OData-Service supports GET-Method which internally calles REST-Service as POST-Method.

      Hope, above clears all the doubt.

      Thanks & Regards,

      Dilip