Skip to Content
Technical Articles
Author's profile photo Andre Fischer

How to use the OData Client Proxy in older SAP S/4 HANA releases (prior 2021)

Updates

  • 29.04.2020 – added picture and scenario description, list of applicable releases
  • 18.10.2022 – added clarification that this is a workaround that can be used in older SAP S/4HANA releases.

Introduction

If you want to consume an OData service in your ABAP coding there is a nice feature available in SAP Cloud Platform, ABAP Environment that lets you generate an OData Client Proxy by importing the EDMX file of an OData V2 service. The import is offered by creating a so called Service Consumption Model.

Though the OData Client Proxy itself is also available in SAP S/4HANA 1709 and later, the Service Consumption Model is only available in SAP S/4HANA as of SAP S/4HANA 2021.

So if you are using SAP S/4HANA 2021 or later you can stop reading at this point and can check out the following tutorial.

https://developers.sap.com/tutorials/abap-environment-create-service-consumption-model.html

Workaround for older SAP S/4HANA releases

The way how to create an odata client proxy model which I will describe in this blog post is meant as a workaround that can be used by customers that are using SAP S/4HANA releases prior 2021 (e.g. 1909 or 2020).

So how can you use the OData Client Proxy without having the option to generate it by creating a Service Consumption Model?

The problem when using the OData Client Proxy is that it requires an OData V4 model which is conveniently created for you in SAP Cloud Platform, ABAP Environment when you create a Service Consumption Model.

Since creating an OData V4 model manually just from analyzing the $metadata document of the OData V2 service that you want to consume is a tedious and error-prone task I thought whether there are workarounds that can be used.

When thinking about the problem it came to my mind that the Service Builder offers the possibility to generate an OData V2 service by importing the $metadata file of remote OData V2 service. Though this will not generate the desired OData V4 model as a result a  V2 model provider class is generated which contains code (TYPES and ABAP code). These artefacts can partly be reused using Cut&Paste when creating a OData V4 model provider class for your OData Client Proxy.

The steps you have to follow are the following:

  1. Create a Service Builder project and import the $metadata file
  2. Get the TYPES statement that has been generated for the structure of the entity type(s) you want to consume
  3. Check the entity type specific define method of the entity type to retrieve the Edm Names of the properties of the entity set.

 

Use case

The use case is the integration of any OData service punlished by other SAP systems that run on premise or in the cloud or other OData services.

In this blog I will describe how to call the Sales Order A2X service that can reside either in another SAP S/4 HANA system (on premise or cloud) from a SAP S/4HANA on premise system.

You can find more information about this service in the SAP API Business Hub.

We will retrieve a list of sales orders using the following OData call

/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder?$top=5

 

Applicable releases

The scenario described can not only be implemented in SAP S/4HANA 1909 but also in the following releases since the SAP Gateway Framework has been down ported as described in SAP Note 2512479 – SAP Gateway Foundation Support Package Stack Definition

  • SAP S/4HANA 2020 SP00
  • SAP S/4HANA 1909 SP01
  • SAP S/4HANA 1809 SP03
  • SAP S/4HANA 1709 (SAP NetWeaver 7.52 SP05)
  • SAP S/4HANA 1609 (SAP NetWeaver 7.51 SP09)
  • SAP NetWeaver 7.52 SP05
  • SAP NetWeaver 7.51 SP09

Create a Service Builder Project

  • We start by creating a new project Z_CONSUME_SO in the Service Builder (transaction SEGW), right click on the folder Data Model and select Import –> Data Model from File from the context menu.

  • Select the EDMX file of your OData Service. In this example I chose the EDMX file of the OData service API_SALES_ORDER_SRV that is part of SAP S/4 HANA and contains lots of entity sets.

  • We now can generate the project which amongst other repository objects will generate a model provider class ZCL_Z_CONSUME_SO_MPC. You can ignore the warnings.

  • If you check the code you will find the type definition for the type TS_A_SALESORDERTYPE.

So in the generated code we will find code snippets that we will reuse in the following step.

This is the entity type specific define method DEFINE_A_SALESORDERTYPE.

 method DEFINE_A_SALESORDERTYPE.
*&---------------------------------------------------------------------*
*&           Generated code for the MODEL PROVIDER BASE CLASS         &*
*&                                                                     &*
*&  !!!NEVER MODIFY THIS CLASS. IN CASE YOU WANT TO CHANGE THE MODEL  &*
*&        DO THIS IN THE MODEL PROVIDER SUBCLASS!!!                   &*
*&                                                                     &*
*&---------------------------------------------------------------------*


  data:
        lo_annotation     type ref to /iwbep/if_mgw_odata_annotation,                "#EC NEEDED
        lo_entity_type    type ref to /iwbep/if_mgw_odata_entity_typ,                "#EC NEEDED
        lo_complex_type   type ref to /iwbep/if_mgw_odata_cmplx_type,                "#EC NEEDED
        lo_property       type ref to /iwbep/if_mgw_odata_property,                  "#EC NEEDED
        lo_entity_set     type ref to /iwbep/if_mgw_odata_entity_set.                "#EC NEEDED

***********************************************************************************************************************************
*   ENTITY - A_SalesOrderType
***********************************************************************************************************************************

lo_entity_type = model->create_entity_type( iv_entity_type_name = 'A_SalesOrderType' iv_def_entity_set = abap_false ). "#EC NOTEXT
lo_entity_type->set_label_from_text_element( iv_text_element_symbol = '002' iv_text_element_container = gc_incl_name ).   "#EC NOTEXT

***********************************************************************************************************************************
*Properties
***********************************************************************************************************************************

lo_property = lo_entity_type->create_property( iv_property_name = 'SalesOrder' iv_abap_fieldname = 'SALESORDER' ). "#EC NOTEXT
lo_property->set_label_from_text_element( iv_text_element_symbol = '003' iv_text_element_container = gc_incl_name ).  "#EC NOTEXT
lo_property->set_is_key( ).
lo_property->set_type_edm_string( ).
lo_property->set_maxlength( iv_max_length = 10 ). "#EC NOTEXT
lo_property->set_creatable( abap_true ).
lo_property->set_updatable( abap_true ).
lo_property->set_sortable( abap_true ).
lo_property->set_nullable( abap_false ).
lo_property->set_filterable( abap_true ).
lo_property->/iwbep/if_mgw_odata_annotatabl~create_annotation( 'sap' )->add(
      EXPORTING
        iv_key      = 'unicode'
        iv_value    = 'false' ).

Of special interest here is the code iv_property_name = ‘SalesOrder’ that sets the external EDM (=Entity Data Model) name of the property of an entity type. For example:

lo_property = lo_entity_type->create_property( iv_property_name = 'SalesOrder' iv_abap_fieldname = 'SALESORDER' ). "#EC NOTEXT

As well as the TYPES definition ts_a_salesordertype that we will use to receive the returned data

types:
  begin of TS_A_SALESORDERTYPE,
     SALESORDER type C length 10,
     SALESORDERTYPE type C length 4,
     SALESORGANIZATION type C length 4,
     DISTRIBUTIONCHANNEL type C length 2,
     ORGANIZATIONDIVISION type C length 2,
     SALESGROUP type C length 3,
     SALESOFFICE type C length 4,
     SALESDISTRICT type C length 6,
     SOLDTOPARTY type C length 10,
     CREATIONDATE type TIMESTAMP,
...
     OVERALLTOTALDELIVERYSTATUS type C length 1,
     OVERALLSDDOCUMENTREJECTIONSTS type C length 1,
  end of TS_A_SALESORDERTYPE .
  types:
TT_A_SALESORDERTYPE type standard table of TS_A_SALESORDERTYPE .

Please note that we have to change the data type for the fields that contain dates such as CREATIONDATE from timestamp to tzntstmps.

 

Create an OData V4 model provider class

As described in one of my previous blogs OData V4 code based implementation I (basic interface, read access) you can create an OData V4 model provider class which inherits from the super class /iwbep/cl_v4_abs_model_prov.

Please note:

  1. You have to replace the type timestamp by the type tzntstmps. If you do not do this when calling the OData Client Proxy you will receive the exception:
    Entity list could not be deserialized.
  2. You have to copy the statementsiv_property_name = ‘SalesOrderType’.from the method DEFINE_A_SALESORDERTYPE to create the coding shown below that sets the correct Edm.Name for the entity set that you want to consume.If you do not do this the OData Client Proxy will return no data, that means you will get a list that only contains empty fields.

CLASS zcl_api_sales_order_srv_v4_mdl DEFINITION
  PUBLIC
  INHERITING FROM /iwbep/cl_v4_abs_model_prov
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    METHODS /iwbep/if_v4_mp_basic~define REDEFINITION.
  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS define_salesorder
      IMPORTING
        io_model TYPE REF TO /iwbep/if_v4_med_model
      RAISING
        /iwbep/cx_gateway .

    TYPES:
      BEGIN OF ts_a_salesordertype,
        salesorder                    TYPE c LENGTH 10,
        salesordertype                TYPE c LENGTH 4,
        salesorganization             TYPE c LENGTH 4,
        distributionchannel           TYPE c LENGTH 2,
        organizationdivision          TYPE c LENGTH 2,
        salesgroup                    TYPE c LENGTH 3,
        salesoffice                   TYPE c LENGTH 4,
        salesdistrict                 TYPE c LENGTH 6,
        soldtoparty                   TYPE c LENGTH 10,
        creationdate                  TYPE tzntstmps,
        createdbyuser                 TYPE c LENGTH 12,
        lastchangedate                TYPE tzntstmps,
        lastchangedatetime            TYPE tzntstmps,
        purchaseorderbycustomer       TYPE c LENGTH 35,
        customerpurchaseordertype     TYPE c LENGTH 4,
        customerpurchaseorderdate     TYPE tzntstmps,
        salesorderdate                TYPE tzntstmps,
        totalnetamount                TYPE p LENGTH 9 DECIMALS 3,
        transactioncurrency           TYPE c LENGTH 5,
        sddocumentreason              TYPE c LENGTH 3,
        pricingdate                   TYPE tzntstmps,
        requesteddeliverydate         TYPE tzntstmps,
        shippingcondition             TYPE c LENGTH 2,
        completedeliveryisdefined     TYPE flag,
        shippingtype                  TYPE c LENGTH 2,
        headerbillingblockreason      TYPE c LENGTH 2,
        deliveryblockreason           TYPE c LENGTH 2,
        incotermsclassification       TYPE c LENGTH 3,
        incotermstransferlocation     TYPE c LENGTH 28,
        incotermslocation1            TYPE c LENGTH 70,
        incotermslocation2            TYPE c LENGTH 70,
        incotermsversion              TYPE c LENGTH 4,
        customerpaymentterms          TYPE c LENGTH 4,
        paymentmethod                 TYPE c LENGTH 1,
        assignmentreference           TYPE c LENGTH 18,
        referencesddocument           TYPE c LENGTH 10,
        referencesddocumentcategory   TYPE c LENGTH 4,
        customertaxclassification1    TYPE c LENGTH 1,
        taxdeparturecountry           TYPE c LENGTH 3,
        vatregistrationcountry        TYPE c LENGTH 3,
        salesorderapprovalreason      TYPE c LENGTH 4,
        salesdocapprovalstatus        TYPE c LENGTH 1,
        overallsdprocessstatus        TYPE c LENGTH 1,
        totalcreditcheckstatus        TYPE c LENGTH 1,
        overalltotaldeliverystatus    TYPE c LENGTH 1,
        overallsddocumentrejectionsts TYPE c LENGTH 1,
      END OF ts_a_salesordertype .

    DATA ls_salesorder TYPE ts_a_salesordertype.

ENDCLASS.



CLASS zcl_api_sales_order_srv_v4_mdl IMPLEMENTATION.

  METHOD /iwbep/if_v4_mp_basic~define.
    define_salesorder( io_model ).
    io_model->set_schema_namespace( 'API_SALES_ORDER_SRV' ).
  ENDMETHOD.

  METHOD define_salesorder.
    DATA: lt_primitive_properties TYPE /iwbep/if_v4_med_element=>ty_t_med_prim_property,
          lo_entity_set           TYPE REF TO /iwbep/if_v4_med_entity_set,
          lo_nav_prop             TYPE REF TO /iwbep/if_v4_med_nav_prop,
          lo_entity_type          TYPE REF TO /iwbep/if_v4_med_entity_type
          ",
          "lv_referenced_cds_view  type gty_cds_views-salesorder
          . " As internal ABAP name we use the name of the CDS view

    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    "   Create entity type
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    lo_entity_type = io_model->create_entity_type_by_struct(
                      EXPORTING
                        iv_entity_type_name          = 'SALESORDER'
                        is_structure                 = ls_salesorder
                        iv_add_conv_to_prim_props    = abap_true
                        iv_add_f4_help_to_prim_props = abap_true
                        iv_gen_prim_props            = abap_true ).

    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " Set external EDM name for entity type
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    lo_entity_type->set_edm_name( 'A_SalesOrderType' ).

    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " Rename external EDM names of properties so that CamelCase notation is used
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    lo_entity_type->get_primitive_properties( IMPORTING et_property = lt_primitive_properties ).

    LOOP AT lt_primitive_properties INTO DATA(lo_primitive_property).
      lo_primitive_property->set_edm_name( to_mixed( val = lo_primitive_property->get_internal_name( ) ) ).
    ENDLOOP.

    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " Set key field(s)
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    lo_primitive_property = lo_entity_type->get_primitive_property( 'SALESORDER' ).
    lo_primitive_property->set_is_key( ).
    lo_primitive_property->set_edm_name( 'SalesOrder' ).

    "Set edm names
    DATA lt_fieldnames TYPE TABLE OF /iwbep/if_v4_med_element=>ty_e_med_edm_name.
    DATA iv_property_name TYPE /iwbep/if_v4_med_element=>ty_e_med_edm_name .

    iv_property_name = 'SalesOrderType'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SalesOrganization'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'DistributionChannel'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'OrganizationDivision'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SalesGroup'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SalesOffice'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SalesDistrict'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SoldToParty'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'CreationDate'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'CreatedByUser'.
    APPEND iv_property_name TO lt_fieldnames.
    "can be null
    iv_property_name = 'LastChangeDate'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'LastChangeDateTime'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'PurchaseOrderByCustomer'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'CustomerPurchaseOrderType'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'customerpurchaseorderdate'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'salesorderdate'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'TotalNetAmount'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'TransactionCurrency'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SDDocumentReason'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'PricingDate'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'RequestedDeliveryDate'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'ShippingCondition'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'CompleteDeliveryIsDefined'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'ShippingType'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'HeaderBillingBlockReason'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'DeliveryBlockReason'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'IncotermsClassification'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'IncotermsTransferLocation'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'IncotermsLocation1'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'IncotermsLocation2' .
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'IncotermsVersion'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'CustomerPaymentTerms'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'PaymentMethod'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'AssignmentReference'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'ReferenceSDDocument'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'ReferenceSDDocumentCategory'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'CustomerTaxClassification1'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'TaxDepartureCountry' .
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'VATRegistrationCountry'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SalesOrderApprovalReason' .
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'SalesDocApprovalStatus'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'OverallSDProcessStatus' .
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'TotalCreditCheckStatus' .
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'OverallTotalDeliveryStatus'.
    APPEND iv_property_name TO lt_fieldnames.
    iv_property_name = 'OverallSDDocumentRejectionSts'.
    APPEND iv_property_name TO lt_fieldnames.

    LOOP AT lt_fieldnames INTO DATA(ls_fieldname).
      lo_primitive_property = lo_entity_type->get_primitive_property( to_upper( ls_fieldname ) ).
      lo_primitive_property->set_edm_name( ls_fieldname ).
      CASE ls_fieldname.
        WHEN 'LastChangeDate'.
          lo_primitive_property->set_is_nullable( ).
      ENDCASE.
    ENDLOOP.

    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    "   Create entity set
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    lo_entity_set = lo_entity_type->create_entity_set( 'SALESORDER' ).
    lo_entity_set->set_edm_name( 'A_SalesOrder' ).

  ENDMETHOD.


ENDCLASS.

 

Register the OData Client Proxy

Using transaction /n/IWBEP/CP_ADMIN we can now register a new client proxy based on the OData V4 model provider class that we have created in the step before.

If you press the create button you have to provide the following information in order to create the OData Client Proxy model.

Proxy Model ID

ZSC_EDMX_IMPORT

Version 1
Model Provider Class

zcl_api_sales_order_srv_v4_mdl

Description

V4 Model for API_SALES_ORDER_SRV

Package

$TMP

The newly created OData Proxy Model will show up in the list.

 

 

Call the OData Client Proxy

Now we can develop a test class to call the OData service in order to retrieve the first 5 sales orders from the list.

Since for calling the OData Client Proxy we need a http client we will create one based on an existing http destination that you have to create using transaction SM59.

In addition we need to provide the repository id (default) where our model has been created alongside with the Proxy Model ID (see above) and the the version as well as the relative service root URL.

The output of the class that implements the if_oo_adt_classrun interface should now be as follows:

 

 

CLASS zcl_my_odata_proxy DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_my_odata_proxy IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.

    TYPES:
      BEGIN OF ts_a_salesordertype,
        salesorder                    TYPE c LENGTH 10,
        salesordertype                TYPE c LENGTH 4,
        salesorganization             TYPE c LENGTH 4,
        distributionchannel           TYPE c LENGTH 2,
        organizationdivision          TYPE c LENGTH 2,
        salesgroup                    TYPE c LENGTH 3,
        salesoffice                   TYPE c LENGTH 4,
        salesdistrict                 TYPE c LENGTH 6,
        soldtoparty                   TYPE c LENGTH 10,
        creationdate                  TYPE tzntstmps,
        createdbyuser                 TYPE c LENGTH 12,
        lastchangedate                TYPE tzntstmps,
        lastchangedatetime            TYPE tzntstmpsl,
        purchaseorderbycustomer       TYPE c LENGTH 35,
        customerpurchaseordertype     TYPE c LENGTH 4,
        customerpurchaseorderdate     TYPE tzntstmps,
        salesorderdate                TYPE tzntstmps,
        totalnetamount                TYPE p LENGTH 9 DECIMALS 3,
        transactioncurrency           TYPE c LENGTH 5,
        sddocumentreason              TYPE c LENGTH 3,
        pricingdate                   TYPE tzntstmps,
        requesteddeliverydate         TYPE tzntstmps,
        shippingcondition             TYPE c LENGTH 2,
        completedeliveryisdefined     TYPE flag,
        shippingtype                  TYPE c LENGTH 2,
        headerbillingblockreason      TYPE c LENGTH 2,
        deliveryblockreason           TYPE c LENGTH 2,
        incotermsclassification       TYPE c LENGTH 3,
        incotermstransferlocation     TYPE c LENGTH 28,
        incotermslocation1            TYPE c LENGTH 70,
        incotermslocation2            TYPE c LENGTH 70,
        incotermsversion              TYPE c LENGTH 4,
        customerpaymentterms          TYPE c LENGTH 4,
        paymentmethod                 TYPE c LENGTH 1,
        assignmentreference           TYPE c LENGTH 18,
        referencesddocument           TYPE c LENGTH 10,
        referencesddocumentcategory   TYPE c LENGTH 4,
        customertaxclassification1    TYPE c LENGTH 1,
        taxdeparturecountry           TYPE c LENGTH 3,
        vatregistrationcountry        TYPE c LENGTH 3,
        salesorderapprovalreason      TYPE c LENGTH 4,
        salesdocapprovalstatus        TYPE c LENGTH 1,
        overallsdprocessstatus        TYPE c LENGTH 1,
        totalcreditcheckstatus        TYPE c LENGTH 1,
        overalltotaldeliverystatus    TYPE c LENGTH 1,
        overallsddocumentrejectionsts TYPE c LENGTH 1,
      END OF ts_a_salesordertype .
    TYPES:
  tt_a_salesordertype TYPE STANDARD TABLE OF ts_a_salesordertype .

    DATA: lt_salesorder    TYPE tt_a_salesordertype,
          lo_client_proxy  TYPE REF TO /iwbep/if_cp_client_proxy,
          lo_read_request  TYPE REF TO /iwbep/if_cp_request_read_list,
          lo_read_response TYPE REF TO /iwbep/if_cp_response_read_lst.

    DATA lv_relative_service_root TYPE string.

    lv_relative_service_root = '/sap/opu/odata/sap/API_SALES_ORDER_SRV/'.

    TRY.
        "throws an exception if service document cannot be read

        " Using SM59 destination for HTTP client object
        cl_http_client=>create_by_destination(
          EXPORTING
            destination = 'LOCAL_HTTP_AF'
          IMPORTING
            client      = DATA(lo_http_client)
          EXCEPTIONS
            OTHERS      = 0 ).

        IF sy-subrc <> 0.
          out->write( 'error create by http destination').
          EXIT.
        ENDIF.

        lo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_remote_proxy(
           io_http_client = lo_http_client
           is_proxy_model_key = VALUE #( repository_id = /iwbep/if_cp_registry_types=>gcs_repository_id-default
           proxy_model_id = 'ZSC_EDMX_IMPORT'
           proxy_model_version = 0001 )
           iv_relative_service_root = lv_relative_service_root ).

         " 'SALESORDER' is the ABAP internal name of the entityset of the V4 model

        lo_read_request = lo_client_proxy->create_resource_for_entity_set( 'SALESORDER' )->create_request_for_read( ).
        lo_read_request->set_top( iv_top = 5 ).

        lo_read_response = lo_read_request->execute( ).

        " Retrieve the business data
        lo_read_response->get_business_data( IMPORTING et_business_data = lt_salesorder ).

        LOOP AT lt_salesorder INTO DATA(ls_salesorder).
          out->write( ls_salesorder ).
        ENDLOOP.

      CATCH /iwbep/cx_cp_remote INTO DATA(lx_cp_remote).
        " Error handling
        out->write( lx_cp_remote->get_longtext(  ) ).
      CATCH /iwbep/cx_gateway INTO DATA(lx_gateway).
        " Error Handling
        out->write( lx_gateway->get_longtext(  ) ).
    ENDTRY.

  ENDMETHOD.

ENDCLASS.

 

 

 

 

Assigned Tags

      13 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Atanu Mallik
      Atanu Mallik

      Nice Feature from Gateway and a nice blog 🙂

      Author's profile photo Abhijeet Kankani
      Abhijeet Kankani

      Hi Andre,

      Nice trick to use existing segw framework and use.

      For consuming odata service in abap there is already "Odata Services Consumption and Integration(OSCI).

      Is iOSCI different from Service Consumption Model and do we expect in upcoming release on sap on-premises will come with odata V4 in both inbound and outbound.

       

      Regards,

      Abhijeet Kankani

      Author's profile photo Andre Fischer
      Andre Fischer
      Blog Post Author

      Hi Abhijeet,

      I know that OSCI is available but I would not recommend to use it anymore if you can use the OData Client Proxy as an alternative.

      The Client Proxy is much more powerful and lets you call an OData service from within your ABAP code.

      OSCI just creates another OData service based on a $metadata file. So no use for you if you want to integrate with an Odata service programmatically. In addition OSCI has lots of technical restrictions.

      OData V4 is available on premise already, inbound and outbound. But you have to create your services and OData client proxies manually.

      Only in an upcoming version the ABAP RESTful programming model will support OData V4.

      This is planned for 2021.

      Regards,

      Andre

       

       

      Author's profile photo Abhijeet Kankani
      Abhijeet Kankani

      Thanks Andre,

       

      Thanks for the update, I only meant using abap restful programming  model for odata v4.

       

      As doing code based implementation for odata V4 is tedious and error prone which you already mentioned in your v4 blog, we cant use cds as RDS there for v4.

      Regards

      Abhijeet kankani

       

      Author's profile photo Pooja Goel
      Pooja Goel

      Hi Andre,

      Can we create dynamic entity set using V4?

      Do we have any mechanism to read the input parameter before creating an entity set?

      Please help me to understand whether it is doable via Odata v2 or V4.

      Thanks

      Pooja

       

      Author's profile photo Andre Fischer
      Andre Fischer
      Blog Post Author

      In the following blog post a community member described how to develop a dynamic entity set.

      https://blogs.sap.com/2018/02/11/create-dynamic-entity-model-in-sap-gateway/

      But you have to be aware that the metadata is cached and you would have to make sure that it would be generated newly with each call which is not a nice thing from a performance perspective.

      Author's profile photo Peter Walcz
      Peter Walcz

      Hi Andre,

       

      is it already / will it be possible to create dynamic entity sets in ABAP Environment (Steampunk)?

       

      Best Regards,

      Peter

      Author's profile photo Pooja Goel
      Pooja Goel

      Hi Andre,

      Thanks!

      I have been through the blog but the way the implementation of dynamic entity has been done is not what I am looking for.

      My requirement is to read the parameter value from the URL & based on which a dynamic entity will get created.

       

      Thanks

      Pooja

      Author's profile photo Adel Yacoubi
      Adel Yacoubi

      Very Useful Tutorial!!

      I get an authentication error when calling the statement :

      lo_client_proxy = /iwbep/cl_cp_client_proxy_fact=>create_v2_remote_proxy(
                 io_http_client = lo_http_client
                 is_proxy_model_key = VALUE #( repository_id = /iwbep/if_cp_registry_types=>gcs_repository_id-default
                 proxy_model_id = 'ZSC_EDMX_IMPORT'
                 proxy_model_version = 0001 )
                 iv_relative_service_root = lv_relative_service_root ).

       

      Is a solution to use a system user on the used destination when creating the http client object?? we do't use single sign on.

      " Using SM59 destination for HTTP client object
              cl_http_client=>create_by_destination(
                EXPORTING
                  destination = 'LOCAL_HTTP_AF'
                IMPORTING
                  client      = DATA(lo_http_client)
                EXCEPTIONS
                  OTHERS      = 0 ).

       

      Thanks in advance

      Kind Regards

      Author's profile photo Andre Fischer
      Andre Fischer
      Blog Post Author

      Yes, this is an option.

      Best regards

      Andre

      Author's profile photo Adel Yacoubi
      Adel Yacoubi

      What are the other options ?

      Author's profile photo Andre Fischer
      Andre Fischer
      Blog Post Author

      Anything that works in SM59

      Author's profile photo aa ok
      aa ok

      Hi, Andre,

      I want to try out the OData Client Proxy to test the service,

      I have successfully get the result list for the EntitySet and single Entity, but couldn't get the $expand item data.

      Could you guide how to achive with url ?$expand=To_Item ?