Extending Your SAP NetWeaver Gateway OData Service – Some ABAP Tips

So – you’ve decided to expose some SAP Business Suite data to outside applications through SAP NetWeaver Gateway.  You’ve seen the ...

Contact us
So – you’ve decided to expose some SAP Business Suite data to outside applications through SAP NetWeaver Gateway.  You’ve seen the tutorials, you’ve read up on how to build services based on RFCs or entirely in custom code, and if you’re really ambitious you’ve even powered your way through the excellent OData and SAP NetWeaver Gateway book from SAP Press.
But if you’re anything like me, you’re chomping at the bit to get neck deep in the ABAP editor and actually crank out some code.  Having worked through the above materials and a couple of my own Gateway service instances, I wanted to share some enhancement and performance tuning thoughts to developers jumping into this product.Before we begin, did you ever notice that when you generate a Gateway service that a bunch of classes are automatically generated?  You can view them in the SEGW transaction, inside your service under the heading “Runtime Artifacts”:

 

We’ll make use of these classes in the below example code.  Note that *_DPC classes are the base, generated classes, while *_EXT classes are subclasses that can be extended for custom purposes.

Now, on to the information!

Know Your BAPIs

If you’ve imported the definition of an RFC BAPI, one of the first things you should do is check the definition for a “max_rows” importing parameter.  A consumer of this OData service can make use of this to restrict processing both on the originating application server as well as sending less data across the wire to the consumer.  Note: not all standard SAP BAPIs make use of this parameter.The most helpful scenario for this is implementing paging in your consuming application.  Let’s say your service is returning a list of contracts to the consumer, and the consuming application wants a single paged subset of the total applicable contracts.  The URI that calls this implementation will look something like:

/sap/opu/odata/sap/ZCONTRACT_SRV/ContractCollection?$top=3&$skip=0


(The parameter $top tells you how big the page is, and $skip tells you where you are in the list.  In this example the consuming application has pages of 3 contracts apiece, and is on the first page.)

Knowing the page size and skip values tells you how many rows you need to pass to your max_rows parameter.  Even if you had the system generate your data access classes through the screens, Gateway’s generated *_DPC classes can be extended via the *_DPC_EXT classes which are also generated at service creation.  For our purposes, the CONTRACTCOLLECTI_GET_ENTITYSET method is where we extend the base class to ensure we pull limited data back.

Here’s some simple sample code:

METHOD CONTRACTCOLLECTI_GET_ENTITYSET.

CHECK it_order[] IS INITIAL.  “See note below

DATA: lv_max_rows TYPE bapimaxrow,
lv_lower_bound TYPE i,
lv_upper_bound TYPE i.

“is_paging is the structure that holds the $top and $skip parameters
lv_max_rows = is_paging-top + is_paging-skip.

“this is a contrived FM – substitute your own!
“note that *_DPC class generates the instance attribute t_contract
“based on the service implementation in SEGW
CALL FUNCTION ‘BAPI_CONTRACTLIST_GET’
EXPORTING
max_rows = lv_max_rows
“your other parameters may need to be here
TABLES
t_contract = t_contract.

“Now if $skip is a nonzero number, you can remove that many
“rows from the top of the table and return the result
lv_lower_bound = is_paging-skip.
IF lines( t_contract ) > is_paging-skip + is_paging-top.
lv_upper_bound = is_paging-skip + is_paging-top.
ELSE.
lv_upper_bound = lines( t_contract ).
ENDIF.
LOOP AT t_contract INTO ls_contract
FROM lv_lower_bound TO lv_upper_bound.
“Logic goes here to move fields to parameter table et_entityset
ENDLOOP.

ENDMETHOD.

Two things to note:

  • Even if you implement your own data population logic without a call to an RFC, if you use ABAP Open SQL to retrieve records you can use the clause “UP TO lv_max_rows ROWS” in your SQL and keep the rest of the logic exactly the same.
  • If the $orderby option is filled, you CANNOT use this logic.  See the very first CHECK in the sample method.

$filter and $select

The URI can also accommodate two other options that can drastically reduce the applicable recordset.  $filter allows you to see any selection options that could reduce the total record count of the result, while $select provides the same functionality as the SELECT clause of an SQL statement: defining the width and properties of the result.There are many ways for which these things could be applicable in a number of RFC or custom code scenarios, but here I’ll show you how to retrieve these options programmatically.  We can use the same redefinition of method as above, as this is applicable to any *_GET_ENTITY or *_GET_ENTITYSET methods in the DPC classes.

METHOD CONTRACTCOLLECTI_GET_ENTITYSET.

“First, retrieve the $select fields
“This is relatively easy, provided by a helper method.
“After invocation, lt_select contains a list of all
“fields needed for the corresponding SELECT statement,
“and to define which fields should be mapped back into
“the et_entityset exporting parameter.
DATA: lt_select TYPE /IWBEP/T_MGW_TECH_FIELD_NAMES.
lt_select = io_tech_request_context->get_select( ).
“Now the $filter data.
“This comes into the method as importing parameter
“it_filter_select_options.  If we were filtering by
“contract ID, we could use code as follows:
DATA: ls_filter_select_options TYPE /iwbep/s_mgw_select_option,
lt_contract_range TYPE RANGE OF contract_id,
ls_contract_range LIKE LINE OF lt_contract_range,
ls_select_option TYPE /iwbep/s_cod_select_option.

“Since any number of select options can be in the table,
“we have to examine it and pull out the relevant information
“for the contract_id range.
LOOP AT it_filter_select_options INTO ls_filter_select_options.
IF ls_filter_select_options-property = ‘ContractID’.
LOOP AT ls_filter_select_options-select_options
INTO ls_select_option.
MOVE-CORRESPONDING ls_select_option TO ls_contract_range.
APPEND ls_contract_range TO lt_contract_range.
ENDLOOP.
ENDIF.
ENDLOOP.

ENDMETHOD.

Customizing Calls to Standard RFCs

Because of the flexibility that the *_EXT classes provide, any time that you define an OData service as based on RFCs you can still implement your own logic alongside the generated code through the extension classes.
Let’s think of a contrived example: in the GET_ENTITY implementation you want to avoid ever passing contract data from a particular customer to the service.  Maybe it’s a top secret government customer that has a requirement that none of their data ever go through an external system.
It’s easy to run your own custom logic and then invoke the standard logic immediately following.  In the *_EXT class we’ve been using, we could do something like this:
METHOD CONTRACTCOLLECTI_GET_ENTITYSET.
  “We’ll monkey with the selection options to always exclude
  “a particular customer and then call the standard super class
  “to continue the operation.
  DATA: lt_filter_select_options TYPE /iwbep/t_mgw_select_option,
        ls_filter_select_options TYPE /iwbep/s_mgw_select_option,
        ls_select_option TYPE /iwbep/s_cod_select_option.
  FIELD-SYMBOLS:
    <ls_filter_select_options> TYPE /iwbep/s_mgw_select_option.
  lt_filter_select_options = it_filter_select_options.
  “Depending on whether there are already filters on customer,
  “we either append another filter to existing ones, or create
  “a new filter altogether.
  “First create the filter to remove all CIA customers from the
  “contract set.
  ls_select_option-sign = ‘E’.  “exclude
  ls_select_option-option = ‘EQ’.
  ls_select_option-low = ‘CIA’.
  “Now either add it to the existing filters or create a new filter.
  READ TABLE lt_filter_select_options ASSIGNING <ls_filter_select_options>
    WITH KEY property = ‘Customer’.
  IF sy-subrc IS INITIAL.
    APPEND ls_select_option TO <ls_filter_select_options>-select_options.
  ELSE.
    ls_filter_select_options-property = ‘Customer’.
    APPEND ls_select_option TO ls_filter_select_options-select_options
    APPEND ls_filter_select_options TO lt_filter_select_options.
  ENDIF.
  “Now that we’ve changed the filter parameters to fit our needs,
  “we can call the super class method with our changed parameter
  “keeping everything else the same
  CALL METHOD super->contractcollecti_get_entityset
EXPORTING
iv_entity_name           = iv_entity_name
iv_entity_set_name       = iv_entity_set_name
iv_source_name           = iv_source_name
it_filter_select_options = lt_filter_select_options
is_paging                = is_paging
it_key_tab               = it_key_tab
it_navigation_path       = it_navigation_path
it_order                 = it_order
iv_filter_string         = iv_filter_string
iv_search_string         = iv_search_string
io_tech_request_context  = io_tech_request_context
IMPORTING
et_entityset             = et_entityset
es_response_context      = es_response_context.
ENDMETHOD.

Summary

If reading ABAP code doesn’t bore you to tears, I hope I’ve given you some information that will help you along the way to creating a high performance Gateway service.  The important takeaway here: even though you get a set of generated code by defining your Gateway service through the GUI in SEGW, you can still use the extension classes to really fine-tune the performance details.
Coming soon:
  • Tips for making sure that your NetWeaver Gateway service is configured for performance
  • Tips for making sure that your SAPUI5 application makes good use of your Gateway services
  • Writing ABAP code to consume an external RESTful web service and expose it to Gateway
Paul J. Modderman

Paul J. Modderman

Paul Modderman loves creating things and sharing them. He has spoken at SAP TechEd, multiple ASUG regional events, ASUG Fall Focus, Google DevFest MN, Google ISV Days, and several webinars and SAP community gatherings. Paul's writing has been featured in SAP Professional Journal, on the SAPinsider blog, and the popular Mindset blog. He believes clear communication is just as important as code, but also has serious developer chops. His tech career has spanned web applications with technologies like .NET, Java, Python, and React to SAP soutions in ABAP, OData and SAPUI5. His work integrating Google, Fiori, and Android was featured at SAP SAPPHIRE. Paul was principal technical architect on Mindset's certified solutions CloudSimple and Analytics for BW. He's an SAP Developer Hero, honored in 2017. Paul is the author of two books: Mindset Perspectives: SAP Development Tips, Tricks, and Projects, and SAPUI5 and SAP Fiori: The Psychology of UX Design. His passion for innovative application architecture and tech evangelism shines through in everything he does.

Let’s make your SAP better, together.

  • This field is for validation purposes and should be left unchanged.