SAP Gateway: $expand
A powerful parameter to expand a response with related entities
- OData URI syntax
- Default $expand functionality
- Custom implementation
In OData, $expand is a very powerful query parameter. It allows providing multiple entities and/or entity sets as a response to a single service call. Doing this can vastly improve performance and significantly simplify the code on the service consumer side compared to doing multiple calls subsequently. Although the SAP Gateway framework can handle expands out of the box, implementing custom logic is recommended for performance reasons.
OData URI syntax
OData.org defines the syntax of an $expand query option as a comma-separated list of Navigation Properties. Additionally each Navigation Property can be followed by a forward slash and another Navigation Property to enable identifying a multi-level relationship.
The OData.org reference services contain a few clear examples of expand URI syntax .
Identifies the collection of Categories as well as each of the Products associated with each Category.
Identifies the collection of Categories as well as each of the Products associated with each Category. In addition, the URI also indentifies the Suppliers associated with each Product.
Identifies the set of Products as well as the Category and Suppliers associated with each product.
Default $expand functionality
$expand statements are resolved by the SAP Gateway framework in a generic way out of the box (a so-called “generic expand”).
The framework calls the respective Get_Entity and/or Get_EntitySet methods of the relevant Data Provider Class and puts the results together in a nested structure or table. Naturally a prerequisite for this functionality is that the appropriate navigation properties have been modeled in the Gateway Service Builder (transaction
How does this work?
Since an $expand follows the navigation properties defined in the OData model and the framework knows the associations between each entity as defined in the data model, it knows which methods it needs to call and how to put the results together.
In the standard implementation, several single roundtrips are executed by the gateway runtime when resolving an $expand call. This means that for n leading entities, n database selections are executed for each navigation step specified in the $expand . The framework does not know the business context of the related entities and corresponding data and therefore cannot optimize the database selections or BAPI calls to get all data in a single call. Therefore it is best practice (and recommended by SAP) to always implement the $expand (therefore using the data provider expand) rather than relying on the framework $expand due to performance reasons.
Custom implementation of expands on entities and entity sets can be achieved by redefining the DPC class methods (/
get_expanded_entityset respectively, both part of the interface
/iwbep/if_mgw_appl_srv_runtime. We can fetch all required data ourselves and return the
result in a nested structure or table using these implementations. This approach allows for full flexibility on which expands the framework should handle versus those better suited with a custom implementation. It is possible to handle an $expand partially and let the framework handle certain navigation steps.
Major logical steps
Let’s take a closer look at the major logical steps of a custom $expand implementation in
get_expanded_entity using a fictitious sample call.
Assume this call is used to fetch an airline entity together with the relevant flights:
Define a nested structure (or table) for storing the result data
"Nested result type DATA: BEGIN OF ls_airline_flights. INCLUDE TYPE zcl_zexample_mpc=>ts_airline. DATA: toflights TYPE STANDARD TABLE OF zcl_zexample_mpc=>ts_flight WITH DEFAULT KEY, END OF ls_airline_flights.
Fill a variable of the above type with the fetched data
"Select airline data into corresponding fields of ls_airline_fields "Select flights for airline into table ls_airline_flights-toflights "Copy the nested structure with the expanded airline data to the "data reference that get_expanded_entity returns copy_data_to_ref( EXPORTING is_data = ls_airline_flights CHANGING cr_data = er_entity ).
Let the framework know which navigation propertie you’ve handled:
add a record to exporting parameter
APPEND 'TOFLIGHTS' TO et_expanded_tech_clauses.
As the last step of a custom implementation, the framework needs informing that we have taken care of one or more $expand properties. We do this by adding a line to
et_expanded_tech_clauses specifying the handled navigation property. The parameter - a string table - is filled with a list of handled expand clauses, based on technical navigation property names.
The code snippet below contains a utility method to dynamically fill
et_expanded_tech_clauses with the navigation property names for the current expand call. The method can be called in each implementation of
/iwbep/if_mgw_appl_srv_runtime~get_expanded_entity instead of manually filling the parameter.
CLASS-METHODS get_expanded_tech_clauses IMPORTING !io_tech_request_context TYPE REF TO /iwbep/if_mgw_req_entity RETURNING VALUE(rt_expanded_tech_clauses) TYPE string_table .
METHOD get_expanded_tech_clauses. CONSTANTS comma TYPE c VALUE ','. DATA(lo_tech_request) = CAST /iwbep/cl_mgw_request( io_tech_request_context ). DATA(lv_expand) = to_upper( lo_tech_request->/iwbep/if_mgw_req_entityset~get_expand( ) ). SPLIT lv_expand AT comma INTO TABLE rt_expanded_tech_clauses. ENDMETHOD.
METHOD /iwbep/if_mgw_appl_srv_runtime~get_expanded_entity. "... et_expanded_tech_clauses = zcl_utility_class=>get_expanded_tech_clauses( io_tech_request_context ). ENDMETHOD.