Appearance
Lesson 21 — Companion: OData, Service Consumption Models and Clean Core
This is your reference while following Lesson 21 — Consuming SAP S/4HANA APIs with OData and Clean Core. Use it when you want to understand what a component does or solve an activation problem. It is not a separate project.
1. The one-sentence purpose of Lesson 21
Read product data stored in SAP S/4HANA from an ABAP application running on SAP BTP, using SAP's supported OData integration tools.
In the preceding HTTP Workshop, you learned to send requests such as GET and inspect JSON. Lesson 21 reuses that understanding and introduces a Service Consumption Model (SCM) that makes an OData response usable as familiar ABAP records.
text
BTP ABAP class
|
| connection from communication arrangement
v
OData Client Proxy <--- metadata from Service Consumption Model
|
v
S/4HANA OData Product API
|
| remote response
v
ABAP internal table (generated row structure)2. The four components most often confused
| Component | Beginner explanation | Does it contain live product data? |
|---|---|---|
| OData service | A published API for querying and sometimes changing business data | Its responses do |
| EDMX | The API's machine-readable instruction manual: fields, entities, types | No |
| Service Consumption Model (SCM) | An ADT repository object generated from the EDMX | No |
| OData Client Proxy | ABAP runtime API that sends OData requests and maps responses to ABAP | It receives live data when executed |
What is an EDMX, exactly?
An EDMX file is XML metadata describing the shape of an OData service. It might define an entity such as A_ClfnProductType with properties Product, ProductType, ProductGroup and BaseUnit.
It is created/published by the API provider (SAP for this S/4HANA API), not by the student consuming it. The $metadata endpoint serves metadata; a Product collection request returns actual product records.
The metadata is imported once when you create or regenerate the SCM. The program then performs real requests when it runs.
Does an SCM automatically establish a connection?
No. The SCM describes the remote API; the communication arrangement provides the outbound connection. The runtime code brings them together.
3. The concrete system we use
| Identifier | Purpose |
|---|---|
https://api.sap.com/api/API_CLFN_PRODUCT_SRV/overview | SAP API documentation and metadata download |
API_CLFN_PRODUCT_SRV | Remote OData V2 service ID |
ZBTP_TRIAL_SAP_COM_0309 | Shared-Trial outbound communication scenario, where provisioned |
ZSC_L21_PROD_001 | Example locally created SCM / proxy model ID |
ZSC_L21_PROD_001=>TYS_A_CLFN_PRODUCT_TYPE | Example generated ABAP product row type |
A_CLFN_PRODUCT | Example generated proxy identifier for the product entity set |
DEFAULT | Repository ID from the working generated model |
0001 | Example SCM proxy model version; inspect yours |
A successful HTTP test was previously observed against the shared S/4HANA Product API in a BTP Trial tenant. That proves this architecture can work, not that every student tenant has the same connectivity or that all shared S/4HANA APIs are exposed.
You do not need the GitHub repository for an SAP workshop to execute this lesson. Everything required is described in the guided content; the SAP Help and API documentation URLs are included there.
4. Find the objects in Eclipse ADT
Open the ABAP perspective
Window → Perspective → Open Perspective → Other… → ABAP.
Open your development package in Project Explorer. If it isn't shown, use Window → Show View → Other… → General → Project Explorer.
Create an ABAP class
Right-click package → New → ABAP Class. Alternative: Right-click package → New → Other ABAP Repository Object… → ABAP Class.
Enter an object name such as ZCL_L21_PRODUCT_PROXY_001, finish the wizard, replace the code, then use Ctrl+S, Ctrl+F3, and F9.
Create a Service Consumption Model
Right-click package → New → Other ABAP Repository Object… → Service Consumption Model.
Choose OData as the Remote Consumption Mode, import API_CLFN_PRODUCT_SRV.edmx, review the generated entities, complete the wizard and activate the SCM.
Find the generated ABAP names
Open the SCM editor → A_ClfnProduct → Read List. Read the sample code to find:
abap
repository_id = 'DEFAULT'
proxy_model_id = 'ZSC_L21_PROD_001'
proxy_model_version = '0001'Look for the generated entity set in create_resource_for_entity_set. Open the generated ABAP class and search for TYS_A_CLFN_PRODUCT_TYPE in its public type declarations. Use your actual names if different.
5. What the ABAP client calls mean
The guided class follows this pattern:
abap
"1. Connection
DATA(lo_destination) =
cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'ZBTP_TRIAL_SAP_COM_0309'
).
DATA(lo_http_client) =
cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
"2. OData model + client proxy
DATA(lo_proxy) =
/iwbep/cl_cp_factory_remote=>create_v2_remote_proxy(
is_proxy_model_key = VALUE #(
repository_id = 'DEFAULT'
proxy_model_id = 'ZSC_L21_PROD_001'
proxy_model_version = '0001'
)
io_http_client = lo_http_client
iv_relative_service_root = ''
).
"3. One collection and a read request
DATA(lo_request) =
lo_proxy->create_resource_for_entity_set(
'A_CLFN_PRODUCT'
)->create_request_for_read( ).
lo_request->set_top( 5 ).The example above is a fragment, not a standalone class. Use the complete runnable class in the guided lesson for execution.
Why is iv_relative_service_root = '' empty?
For this specific shared Trial configuration, the outbound destination already points to the Product OData service root. Adding the full service path a second time would risk an incorrect URL.
Other real landscapes may configure only the host in the destination and therefore require a nonempty relative service root. Do not copy the empty string blindly into unrelated projects; check the destination and the service root used by that project.
Why do we use create_v2_remote_proxy?
The imported Product API metadata describes an OData V2 service, so the example uses a V2 client proxy. OData V4 has a different proxy creation method; do not switch to it without changing the service/model.
Why does get_business_data( ) work?
Your Service Consumption Model provides an ABAP description of the remote entity. The client proxy uses the model to convert the remote OData payload into an internal table whose rows have component fields such as product and product_type.
6. Filtering, paging, and reliable output
An OData collection may contain many products. Do not fetch an unbounded list when you only need a few rows.
Limit the result
abap
lo_request->set_top( 5 ).Requests at most five rows. It is not a guarantee that five exist. Unless you also request a supported sort order, set_top() does not define which five are returned consistently.
Filter on the server
abap
DATA lt_product_range TYPE if_rap_query_filter=>tt_range_option.
lt_product_range = VALUE #(
( sign = 'I' option = 'EQ' low = 'A001' )
).
DATA(lo_filter) =
lo_request->create_filter_factory( )->create_by_range(
iv_property_path = 'PRODUCT'
it_range = lt_product_range
).
lo_request->set_filter( lo_filter ).This corresponds to the idea of $filter=Product eq 'A001'. The proxy handles constructing and encoding the OData filter from the model.
sign = 'I': include matching values.option = 'EQ': equality.low = 'A001': value to match.iv_property_path = 'PRODUCT': proxy property ID taken from the model.
Empty result is not failure. If lt_products is empty after a successful request, the record may not exist or the filter may exclude everything. An exception/HTTP failure is a separate situation.
Avoid dozens of empty fields
The Product type contains many properties for different categories of products. Service products may not have weights, dimensions or warehouse attributes populated.
Display only what the user needs:
abap
LOOP AT lt_products INTO DATA(ls_product).
out->write(
|{ ls_product-product } | &&
|{ ls_product-product_type } | &&
|{ ls_product-product_group }|
).
ENDLOOP.7. Understanding Clean Core and released APIs
A company often extends SAP S/4HANA, but future updates become risky when external custom programs depend on private SAP implementation details.
One Clean Core approach is to keep standard code unchanged and integrate via documented, suitable APIs. Here, the Product API is a published interface for product reads. The custom application operates in BTP and requests data through that interface.
C0, C1 and C2 are not OData versions
| Contract | Core meaning | Typical usage |
|---|---|---|
| C0 — Extend | Defined extension points may be extended | Enhance permitted CDS/RAP behavior |
| C1 — Use System-Internally | Use a released interface from code in the applicable ABAP system | Local released ABAP API consumption |
| C2 — Use as Remote API | Published remote interface for external consumers | BTP to SAP back-end integration |
Always look at the actual API's release status and documentation. Just because an endpoint responds over HTTP does not mean every field, operation or access path is supported for your production use.
Do not confuse Clean Core with the protocol
A generic REST API and an OData API both communicate over HTTP. Clean Core is about depending on supported interfaces and extension points, not whether you used JSON or typed ABAP data.
8. If live connectivity fails: runnable local fallback
This fallback demonstrates typed ABAP table processing. It is not an SCM test, not a remote call, and must never be reported as S/4HANA connectivity success.
Create the class
Right-click package → New → ABAP Class. Name it ZCL_L21_LOCAL_PRODUCTS_001. Replace the source with this complete example:
abap
CLASS zcl_l21_local_products_001 DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_l21_local_products_001 IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"All values are deliberately created locally for this fallback.
TYPES: BEGIN OF ty_product,
product TYPE c LENGTH 40,
product_type TYPE c LENGTH 4,
product_group TYPE c LENGTH 9,
END OF ty_product.
DATA lt_products TYPE STANDARD TABLE OF ty_product
WITH EMPTY KEY.
lt_products = VALUE #(
( product = 'DEMO-001' product_type = 'SERV'
product_group = 'TRAINING' )
( product = 'DEMO-002' product_type = 'SERV'
product_group = 'TRAINING' )
( product = 'DEMO-003' product_type = 'FERT'
product_group = 'TRAINING' )
).
out->write( 'LOCAL SIMULATION — NOT S/4HANA DATA' ).
LOOP AT lt_products INTO DATA(ls_product)
WHERE product_type = 'SERV'.
out->write(
|{ ls_product-product } - { ls_product-product_type }|
).
ENDLOOP.
ENDMETHOD.
ENDCLASS.Activate using Ctrl+F3 and execute using F9.
Expected result:
text
LOCAL SIMULATION — NOT S/4HANA DATA
DEMO-001 - SERV
DEMO-002 - SERVWhy this helps: It lets you practice structures, tables, WHERE, and output while your tenant's outbound connectivity issue is investigated. You can still import and inspect the EDMX/SCM if those tools work, but this local class does not exercise the OData client proxy.
9. Common problems, clearly explained
| Symptom | Likely place to investigate | First action |
|---|---|---|
| Cannot find SCM wizard | ADT version, ABAP project, authorization | Use Other ABAP Repository Object search; confirm ABAP perspective |
| Wizard rejects EDMX | Metadata file/type | Check .edmx XML file and correct Product API |
Unknown tys_a_clfn_product_type | Generated class/type name differs | Open generated class and copy actual type |
Unknown A_CLFN_PRODUCT | Proxy entity set identifier | Copy identifier from SCM Read List code |
proxy_model_id / version mismatch | Generated model key | Copy values from SCM sample |
| Destination not found | Trial scenario access | Confirm ZBTP_TRIAL_SAP_COM_0309 exists/accessible |
| HTTP 401 / 403 | Authentication/authorization | Inspect configured communication arrangement; do not hard-code secrets |
| HTTP 404 | Wrong service path/root | Inspect destination path and iv_relative_service_root |
| Empty result | Filter/data | Change to known test product and retry |
| Many empty columns | API returns a broad data model | Print only relevant properties |
Reading error messages in ADT
Use Window → Show View → Other… → General → Problems to display activation errors. Double-click one to jump to the source. Runtime errors appear in the ABAP Console or ADT error details and should be recorded without credentials or secret headers.
10. Review questions and answers
Q: Who creates the EDMX?
A: The API provider. Here SAP publishes metadata for the Product OData service.
Q: Does an EDMX contain product A001 and its current attributes?
A: No; it describes the structure and service capabilities. An API read request retrieves records.
Q: Does an SCM open an HTTP connection by itself?
A: No. It is a design-time model. Your ABAP code creates a client and executes a request through the configured destination.
Q: Why did direct HTTP return JSON, while the proxy returned a typed ABAP table?
A: The proxy uses metadata from the SCM to map OData responses into generated ABAP types.
Q: Do we always use iv_relative_service_root = ''?
A: No. It is correct for the specific shared Trial destination shown in the guided example. Other destinations may not already point to the service root.
Q: Is OData the same thing as RAP?
A: No. OData is a standard API protocol. RAP is an ABAP development model that can expose and consume services in broader application scenarios.
Q: Are product IDs always A001–B003?
A: No. Those values came from one working demonstration response. A different remote dataset may return different products.
Q: Why not use the JSONPlaceholder service from the HTTP Workshop?
A: It's useful to learn generic REST/HTTP, but it does not supply the OData metadata/service model needed for this SCM exercise.
Q: How will this help later?
A: The next side-by-side integration project can use a remote Product API as a value help or data source for a custom RAP/Fiori application.
11. Reference URLs
- SAP Product API documentation and EDMX: https://api.sap.com/api/API_CLFN_PRODUCT_SRV/overview
- SAP Developer — Outbound OData Call via SCM: https://developers.sap.com/tutorials/abap-environment-business-partner-outbound-call
- SAP Help — Prepare Access to Remote OData: https://help.sap.com/docs/abap-cloud/abap-rap/preparing-access-to-remote-odata-service
- SAP Help — Create a Remote Client Proxy: https://help.sap.com/docs/abap-cloud/abap-rap/creating-remote-client-proxy
- SAP Help — OData Client Proxy User Guide: https://help.sap.com/docs/abap-cloud/abap-integration-connectivity/odata-client-proxy-user-guide
- SAP Help — HTTP Outbound Service and Default Path Prefix: https://help.sap.com/docs/abap-cloud/abap-integration-connectivity/outbound-service
Code verification note: The main proxy class in the guided lesson uses the same model and type patterns that already ran successfully in a BTP Trial tenant. The filtered example and this companion's offline fallback have been reviewed as source, but not activated in your tenant during this file creation.