A comprehensive engineering guide on designing high-throughput, Clean Core compliant Custom Entities in the ABAP RESTful Application Programming Model using IF_RAP_QUERY_PROVIDER.
In standard SAP RAP development, CDS View Entities directly read from underlying database tables (managed data access). However, in modern enterprise architectures, data often originates from sources outside standard CDS capabilities:
To expose these data sources to SAP Fiori elements and OData V4 without violating Clean Core, SAP RAP provides Custom Entities (`define custom entity`) coupled with an ABAP class implementing IF_RAP_QUERY_PROVIDER.
A Custom Entity does not have an SQL view or standard database persistence. It is defined in ADT as follows:
@EndUserText.label: 'External Fleet Telemetry Query'
@ObjectModel.query.implementedBy: 'ABAP:ZCL_CE_TELEMETRY_PROVIDER'
@Search.searchable: true
define custom entity ZCE_FLEET_TELEMETRY {
key vehicle_id : /dmo/vehicle_id;
latitude : abap.fltp;
longitude : abap.fltp;
speed_kmh : abap.dec(5,2);
fuel_level_pct : abap.int2;
last_ping_utc : timestampl;
}
The annotation @ObjectModel.query.implementedBy: 'ABAP:class_name' binds the CDS entity to the query engine execution class.
if_rap_query_provider~selectWhen an OData client or Fiori app performs a GET request against the entity set, the RAP runtime dispatches the request to if_rap_query_provider~select. The method signature receives two essential objects:
io_request (TYPE REF TO if_rap_query_request): Contains query options requested by the client ($filter, $select, $top, $skip, $orderby, $inlinecount, $search).io_response (TYPE REF TO if_rap_query_response): Receives the processed dataset and total record counts.| OData Parameter | RAP Request Method | Implementation Responsibility |
|---|---|---|
$filter |
io_request->get_filter( )->get_as_ranges( ) |
Extract range tables and pass to SQL/RFC/REST query filters. |
$top / $skip |
io_request->get_paging( )->get_page_size( ) / get_offset( ) |
Slice backend response array or forward pagination headers to remote REST API. |
$count |
io_request->is_total_numb_of_rec_requested( ) |
Calculate lines( lt_data ) and set via io_response->set_total_number_of_records( ). |
$orderby |
io_request->get_sort_elements( ) |
Sort data in-memory or forward sort query parameter. |
$select |
io_request->get_requested_elements( ) |
Optimize payload by omitting unrequested expensive attributes. |
A frequent challenge during S/4HANA Clean Core migrations is displaying data from legacy BAPIs that are not yet released for ABAP Cloud (C1 Contract). Direct invocation of unreleased BAPIs in Tier-1 triggers critical ATC errors.
" Inside Tier-2 Quarantined Class: ZCL_TIER2_SALES_WRAPPER
CLASS zcl_tier2_sales_wrapper DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
CLASS-METHODS read_sales_orders
IMPORTING it_filter_ranges TYPE if_rap_query_filter=>tt_name_range_pairs
RETURNING VALUE(rt_orders) TYPE ztt_sales_order_flat.
ENDCLASS.
CLASS zcl_tier2_sales_wrapper IMPLEMENTATION.
METHOD read_sales_orders.
" Classic RFC call permitted here because package language version is 'Standard ABAP'
CALL FUNCTION 'BAPI_SALESORDER_GETLIST'
TABLES
sales_orders = rt_orders.
ENDMETHOD.
ENDCLASS.
Any runtime failure (HTTP 500, RFC connection timeout, JSON parsing error) must be caught and re-raised as cx_rap_query_provider. Failing to handle exceptions properly causes unhandled dumps in the SAP Gateway / ICF layer:
TRY.
" Query and transformation logic
CATCH cx_root INTO DATA(lx_error).
RAISE EXCEPTION TYPE cx_rap_query_provider
EXPORTING
previous = lx_error.
ENDTRY.
Get the complete 400+ page guide with end-to-end architectures, testing patterns, and migration blueprints:
Unlock Complete Enterprise Suite (80% Off • €9.80) → Also available in Paperback & Kindle on Amazon ($19.99)