Skip to content

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 ​

ComponentBeginner explanationDoes it contain live product data?
OData serviceA published API for querying and sometimes changing business dataIts responses do
EDMXThe API's machine-readable instruction manual: fields, entities, typesNo
Service Consumption Model (SCM)An ADT repository object generated from the EDMXNo
OData Client ProxyABAP runtime API that sends OData requests and maps responses to ABAPIt 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 ​

IdentifierPurpose
https://api.sap.com/api/API_CLFN_PRODUCT_SRV/overviewSAP API documentation and metadata download
API_CLFN_PRODUCT_SRVRemote OData V2 service ID
ZBTP_TRIAL_SAP_COM_0309Shared-Trial outbound communication scenario, where provisioned
ZSC_L21_PROD_001Example locally created SCM / proxy model ID
ZSC_L21_PROD_001=>TYS_A_CLFN_PRODUCT_TYPEExample generated ABAP product row type
A_CLFN_PRODUCTExample generated proxy identifier for the product entity set
DEFAULTRepository ID from the working generated model
0001Example 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 ​

ContractCore meaningTypical usage
C0 — ExtendDefined extension points may be extendedEnhance permitted CDS/RAP behavior
C1 — Use System-InternallyUse a released interface from code in the applicable ABAP systemLocal released ABAP API consumption
C2 — Use as Remote APIPublished remote interface for external consumersBTP 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 - SERV

Why 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 ​

SymptomLikely place to investigateFirst action
Cannot find SCM wizardADT version, ABAP project, authorizationUse Other ABAP Repository Object search; confirm ABAP perspective
Wizard rejects EDMXMetadata file/typeCheck .edmx XML file and correct Product API
Unknown tys_a_clfn_product_typeGenerated class/type name differsOpen generated class and copy actual type
Unknown A_CLFN_PRODUCTProxy entity set identifierCopy identifier from SCM Read List code
proxy_model_id / version mismatchGenerated model keyCopy values from SCM sample
Destination not foundTrial scenario accessConfirm ZBTP_TRIAL_SAP_COM_0309 exists/accessible
HTTP 401 / 403Authentication/authorizationInspect configured communication arrangement; do not hard-code secrets
HTTP 404Wrong service path/rootInspect destination path and iv_relative_service_root
Empty resultFilter/dataChange to known test product and retry
Many empty columnsAPI returns a broad data modelPrint 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 ​

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.