Scenario:
Suppose we need to expose images related to a "PickTicket" from an external system, making them available in SAP via a custom OData service.
Steps Overview
1. Create a Custom Entity CDS View
2. Create Service Definition
3. Create Service Binding
4. Implement ABAP Class to Consume the External API
5. Test the OData Service
1. Create a Custom Entity (CDS View)
Start by defining a **custom entity** to represent the data structure for the API response:
@EndUserText.label: 'Custom Entity for Image Data'
@ObjectModel: {
query: {
implementedBy: 'ABAP:ZCL_IMAGESET'
}
}
define root custom entity ZCE_IMAGESET
{
key pickticketid : abap.char(20);
key urlshortlivedthumbnail : abap.char(255);
trigger_ : abap.char(20);
source : abap.char(40);
imageid : abap.char(20);
urlthumbnail : abap.char(255);
urlshortlived : abap.char(255);
}This entity acts as a **virtual view**—data retrieval is handled by an ABAP class (see `implementedBy` above).
2. Create a Service Definition
Expose the custom entity in your service definition:
@EndUserText.label: 'zsd_imageset'
define service Zsd_imageset {
expose ZCE_IMAGESET;
}3. Create a Service Binding
Next, create a **service binding**—for example, `ZSB_IMAGESET` for OData V4—which generates the OData endpoint for your application. *Use the standard RAP tools in Eclipse or ADT to create this binding from the CDS service definition.*
4. Implement the ABAP Class to Handle API Call
Define the ABAP class (`zcl_imageset`) to fetch and provide data from the external API.
Use the **RAP Query Provider Interface** (`if_rap_query_provider`) for custom data provisioning:
Class Definition
CLASS zcl_imageset DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
TYPES: BEGIN OF ty_imageset,
trigger TYPE char20,
pickticketid TYPE char20,
source TYPE char40,
imageid TYPE char20,
urlthumbnail TYPE char255,
urlshortlived TYPE char255,
urlshortlivedthumbnail TYPE char255,
END OF ty_imageset.
TYPES: tt_imageset TYPE STANDARD TABLE OF ty_imageset WITH EMPTY KEY.
INTERFACES if_rap_query_provider.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.Class Implementation
CLASS ZCL_IMAGESET IMPLEMENTATION.
METHOD if_rap_query_provider~select.
DATA lt_images TYPE tt_imageset.
DATA lv_pickticketid TYPE string.
" Get filter (PickTicketId)
DATA(lo_filter) = io_request->get_filter( )->get_as_sql_string( ).
DATA(lv_offset) = io_request->get_paging( )->get_offset( ).
DATA(lv_page_size) = io_request->get_paging( )->get_page_size( ).
DATA(lv_max_rows) = COND #( WHEN lv_page_size = if_rap_query_paging=>page_size_unlimited THEN 0
ELSE lv_page_size ).
DATA(lt_sort_table) = VALUE string_table( FOR ls_sort_element IN io_request->get_sort_elements( )
( ls_sort_element-element_name && COND #( WHEN ls_sort_element-descending = abap_true THEN ` descending` ELSE ` ascending` ) ) ).
CONCATENATE 'PICKTICKETID ' 'SOURCE'
INTO DATA(lv_default_sort) SEPARATED BY ',' .
DATA(lv_sort_string) = COND #( WHEN lt_sort_table IS INITIAL THEN lv_default_sort
ELSE concat_lines_of( table = lt_sort_table sep = ',' ) ).
IF io_request IS BOUND.
DATA(lt_expressions) = io_request->get_filter( )->get_as_ranges( ).
LOOP AT lt_expressions INTO DATA(ls_expr).
IF ls_expr-name = 'PICKTICKETID'.
LOOP AT ls_expr-range INTO DATA(ls_range).
IF ls_range-option = 'EQ'.
lv_pickticketid = ls_range-low.
EXIT.
ENDIF.
ENDLOOP.
EXIT.
ENDIF.
ENDLOOP.
ENDIF.
" Build target URL for the external request
DATA(lv_url) = |https://<external domain url>/pickTickets/{ lv_pickticketid }/images|.
" Create HTTP client and set headers
DATA lo_http_client TYPE REF TO if_http_client.
cl_http_client=>create_by_url(
EXPORTING url = lv_url
IMPORTING client = lo_http_client
).
lo_http_client->request->set_header_field( name = 'client_id' value = '<your_client_id>' ).
lo_http_client->request->set_header_field( name = 'client_secret' value = '<your_client_secret>' ).
lo_http_client->send( ).
lo_http_client->receive( ).
DATA(lv_response) = lo_http_client->response->get_cdata( ).
lo_http_client->close( ).
" Parse JSON response to ABAP table
DATA(lo_json) = NEW /ui2/cl_json( ).
lo_json->deserialize(
EXPORTING json = lv_response
CHANGING data = lt_images
).
" Return the data
io_response->set_total_number_of_records( lines( lt_images ) ).
io_response->set_data( lt_images ).
ENDMETHOD.
ENDCLASS.*Replace* `<external domain url>`, `<your_client_id>`, and `<your_client_secret>` *with real values.*
5. Publish and Test Your OData Service
Key Takeaways
Conclusion
You now have a **custom OData service** in SAP S/4HANA PCE, powered by the RAP framework, which brings in dynamic data from an **external API**. You can enhance, secure, and extend this pattern for many integration use cases—be it analytics dashboards, mobile apps, or UI5/Fiori apps!
Let me know your feedback, or reach out for specific questions.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 19 | |
| 11 | |
| 9 | |
| 6 | |
| 5 | |
| 5 | |
| 3 | |
| 3 | |
| 3 | |
| 3 |