Das Service Consumption Model (SCM) ist der empfohlene Weg, externe REST- und OData-APIs in ABAP Cloud typsicher zu konsumieren. Im Gegensatz zum direkten HTTP-Client-Aufruf generiert das SCM automatisch ABAP-Proxyklassen und Datentypen aus der API-Spezifikation - das spart Entwicklungszeit und verhindert Fehler.
Übersicht: SCM vs. HTTP Client
| Aspekt | Service Consumption Model | HTTP Client direkt |
|---|---|---|
| Typsicherheit | Vollständig - generierte Typen | Keine - manuelle JSON-Verarbeitung |
| Aufwand | Einmalig: Import + Konfiguration | Jeder Aufruf: Request bauen, Response parsen |
| Wartbarkeit | Hoch - API-Änderungen sichtbar | Niedrig - Fehler erst zur Laufzeit |
| Flexibilität | Eingeschränkt auf definierte APIs | Maximale Flexibilität |
| Use Case | Stabile externe APIs (OData, OpenAPI) | Ad-hoc-Aufrufe, dynamische APIs |
Wann welchen Ansatz wählen?
Service Consumption Model nutzen wenn:
- Du eine stabile OData- oder REST-API konsumierst
- Die API eine EDMX- oder OpenAPI-Spezifikation hat
- Typsicherheit und Wartbarkeit wichtig sind
- Mehrere API-Operationen genutzt werden
HTTP Client direkt nutzen wenn:
- Die API keine formale Spezifikation hat
- Du nur wenige, einfache Aufrufe brauchst
- Die API sich häufig ändert
- Du maximale Kontrolle über Request/Response benötigst
Für Details zum direkten HTTP-Client-Ansatz siehe ABAP HTTP Client: REST-APIs aufrufen.
Unterstützte API-Formate
Das Service Consumption Model unterstützt drei Formate:
┌─────────────────────────────────────────────────────────────────────────┐│ Service Consumption Model - Unterstützte Formate │├─────────────────────────────────────────────────────────────────────────┤│ ││ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ ││ │ OData V2 (EDMX) │ │ OData V4 (EDMX) │ │ OpenAPI 3.0 │ ││ │ │ │ │ │ (JSON/YAML) │ ││ │ - SAP Standard │ │ - Modernes OData │ │ - REST APIs │ ││ │ - S/4HANA APIs │ │ - RAP Services │ │ - Externe APIs │ ││ │ - SuccessFactors │ │ - BTP Services │ │ - Cloud APIs │ ││ └─────────────────────┘ └─────────────────────┘ └─────────────────┘ ││ ││ Import in ADT: ││ File → New → Other ABAP Repository Object ││ → Connectivity → Service Consumption Model │└─────────────────────────────────────────────────────────────────────────┘Schritt-für-Schritt: SCM erstellen
1. API-Spezifikation beschaffen
Zuerst benötigst du die EDMX- oder OpenAPI-Datei der Ziel-API:
OData-APIs (EDMX):
# SAP API Business Hubhttps://api.sap.com → API auswählen → API Specification → Download EDMX
# Aus laufendem SAP-SystemGET https://<host>/sap/opu/odata/sap/<SERVICE_NAME>/$metadataREST-APIs (OpenAPI):
# Öffentliche APIshttps://api.example.com/openapi.jsonhttps://api.example.com/swagger.json
# SAP BTP Serviceshttps://api.sap.com → Service auswählen → Download OpenAPI spec2. Service Consumption Model anlegen
In ADT (ABAP Development Tools):
- Rechtsklick auf Package → New → Other ABAP Repository Object
- Kategorie: Connectivity → Service Consumption Model
- Wizard ausfüllen:
| Feld | Beispielwert | Beschreibung |
|---|---|---|
| Name | ZSCM_WEATHER_API | Technischer Name |
| Description | Weather API Consumer | Kurzbeschreibung |
| Remote Consumption Mode | OData oder Web Service | API-Typ |
- Metadaten-Datei importieren (EDMX, OpenAPI JSON, oder WSDL)
- Finish - ADT generiert alle Artefakte
3. Generierte Artefakte verstehen
Nach dem Import findest du folgende Objekte:
ZSCM_WEATHER_API (Service Consumption Model)│├── ZSCM_WEATHER_API_PROXY (Proxy-Klasse)│ ├── get_weather_forecast() " Operation aus API│ ├── get_current_weather() " Operation aus API│ └── create_alert() " Operation aus API│├── ZS_WEATHER_FORECAST (Struktur)│ ├── location TYPE string│ ├── temp_min TYPE decfloat16│ └── temp_max TYPE decfloat16│├── ZS_CURRENT_WEATHER (Struktur)│ └── ...│└── ZCX_WEATHER_API (Exception-Klasse) └── Fachliche/technische FehlerCode-Beispiel: API-Aufruf mit SCM-Proxy
Voraussetzung: Communication Arrangement
Bevor der Proxy funktioniert, benötigst du die Verbindungskonfiguration. Siehe Communication Scenarios Guide für Details.
Proxy-Aufruf implementieren
CLASS zcl_weather_service DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_weather_result, location TYPE string, temperature TYPE decfloat16, humidity TYPE i, success TYPE abap_bool, error_msg TYPE string, END OF ty_weather_result.
METHODS get_weather IMPORTING iv_location TYPE string RETURNING VALUE(rs_result) TYPE ty_weather_result.
ENDCLASS.
CLASS zcl_weather_service IMPLEMENTATION.
METHOD get_weather. " Destination über Communication Arrangement holen DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement( comm_scenario = 'Z_WEATHER_OUTBOUND' service_id = 'Z_WEATHER_API_REST' ).
" Proxy instanziieren DATA(lo_proxy) = NEW zscm_weather_api_proxy( iv_destination = lo_destination ).
TRY. " Typsicherer API-Aufruf - Eingabeparameter als Struktur DATA(ls_request) = VALUE zs_weather_request( location = iv_location units = 'metric' ).
" API aufrufen - Response als generierte Struktur DATA(ls_response) = lo_proxy->get_current_weather( is_request = ls_request ).
" Ergebnis mappen rs_result = VALUE #( location = ls_response-name temperature = ls_response-main-temp humidity = ls_response-main-humidity success = abap_true ).
CATCH zcx_weather_api INTO DATA(lx_api). " Fachlicher Fehler (z.B. Location nicht gefunden) rs_result-success = abap_false. rs_result-error_msg = lx_api->get_text( ).
CATCH cx_http_dest_provider_error cx_web_http_client_error INTO DATA(lx_http). " Technischer Fehler (Netzwerk, Timeout) rs_result-success = abap_false. rs_result-error_msg = |Verbindungsfehler: { lx_http->get_text( ) }|.
ENDTRY. ENDMETHOD.
ENDCLASS.Response-Handling und Mapping
Automatische Typen nutzen
Der große Vorteil des SCM: Du arbeitest mit ABAP-Strukturen statt mit JSON-Strings.
" OHNE SCM - manuelles JSON-ParsingDATA(lv_json) = lo_client->execute( )->get_text( )./ui2/cl_json=>deserialize( EXPORTING json = lv_json CHANGING data = ls_weather)." Fehleranfällig: Feldnamen müssen exakt matchen
" MIT SCM - typsicherDATA(ls_weather) = lo_proxy->get_current_weather( ls_request )." Compiler prüft Struktur, Feldnamen sind garantiert korrektKomplexe Responses verarbeiten
Bei verschachtelten Strukturen nutzt du die generierten Typen:
" Generierte verschachtelte Struktur" zs_forecast_response" ├── city: zs_city" │ ├── name" │ └── country" └── list: TABLE OF zs_forecast_item" ├── dt (timestamp)" ├── main: zs_main_data" │ ├── temp" │ └── humidity" └── weather: TABLE OF zs_weather_desc
DATA(ls_forecast) = lo_proxy->get_forecast( ls_request ).
" Zugriff auf verschachtelte Daten - vollständig typisiertLOOP AT ls_forecast-list INTO DATA(ls_item). DATA(lv_temp) = ls_item-main-temp.
LOOP AT ls_item-weather INTO DATA(ls_desc). " Wetterbeschreibungen verarbeiten DATA(lv_description) = ls_desc-description. ENDLOOP.ENDLOOP.Unterschied: HTTP Client vs. SCM
| Szenario | HTTP Client | Service Consumption Model |
|---|---|---|
| API aufrufen | URL + Method + Body manuell | Methode mit Parametern |
| Request bauen | JSON serialisieren | ABAP-Struktur befüllen |
| Response lesen | JSON deserialisieren | Direkt ABAP-Struktur |
| Fehlertypen | HTTP-Statuscodes prüfen | Spezifische Exceptions |
| API-Änderung | Laufzeitfehler | Compile-Fehler |
Vergleich am Beispiel
" ══════════════════════════════════════════════════════════════════" Ansatz 1: Direkter HTTP Client" ══════════════════════════════════════════════════════════════════DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination( lo_destination).
lo_client->get_http_request( )->set_uri_path( '/weather' ).lo_client->get_http_request( )->set_query_parameter( name = 'q' value = 'Berlin').
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).DATA(lv_json) = lo_response->get_text( ).
" JSON manuell parsen - fehleranfälligDATA: BEGIN OF ls_weather, name TYPE string, main TYPE REF TO data, END OF ls_weather.
/ui2/cl_json=>deserialize( EXPORTING json = lv_json CHANGING data = ls_weather).
lo_client->close( ).
" ══════════════════════════════════════════════════════════════════" Ansatz 2: Service Consumption Model" ══════════════════════════════════════════════════════════════════DATA(lo_proxy) = NEW zscm_weather_api( lo_destination ).
" Typsicherer Aufruf - Compiler validiert ParameterDATA(ls_weather) = lo_proxy->get_current_weather( VALUE #( q = 'Berlin' )).
" Direkter Zugriff auf typisierte FelderDATA(lv_temp) = ls_weather-main-temp.Fehlerbehandlung und Best Practices
Exception-Hierarchie verstehen
TRY. DATA(ls_result) = lo_proxy->get_data( ls_request ).
CATCH zcx_scm_business_error INTO DATA(lx_business). " Fachlicher Fehler - API hat Fehler gemeldet (z.B. 404, 422) " Diese sind NICHT retry-fähig CASE lx_business->http_status. WHEN 404. " Resource nicht gefunden WHEN 422. " Validierungsfehler in Request ENDCASE.
CATCH cx_http_dest_provider_error INTO DATA(lx_dest). " Destination-Fehler - Konfigurationsproblem " Logging, aber kein Retry LOG-POINT ID zlog SUBKEY 'DEST_ERROR' FIELDS lx_dest->get_text( ).
CATCH cx_web_http_client_error INTO DATA(lx_http). " Technischer Fehler - Netzwerk, Timeout " Diese KÖNNEN retry-fähig sein IF lx_http->error_type = if_web_http_client=>co_timeout. " Retry möglich ENDIF.
ENDTRY.Retry-Logik implementieren
CONSTANTS: c_max_retries TYPE i VALUE 3, c_retry_delay TYPE i VALUE 1000. " ms
DATA: lv_attempt TYPE i VALUE 1.
WHILE lv_attempt <= c_max_retries. TRY. DATA(ls_result) = lo_proxy->call_api( ls_request ). EXIT. " Erfolg - Schleife verlassen
CATCH cx_web_http_client_error INTO DATA(lx_http). IF lx_http->error_type = if_web_http_client=>co_timeout AND lv_attempt < c_max_retries. " Warten und erneut versuchen cl_abap_session=>sleep( c_retry_delay * lv_attempt ). lv_attempt = lv_attempt + 1. ELSE. " Kein Retry mehr möglich RAISE EXCEPTION TYPE zcx_api_call_failed EXPORTING textid = zcx_api_call_failed=>api_unavailable previous = lx_http. ENDIF. ENDTRY.ENDWHILE.Best Practices Checkliste
| Best Practice | Beschreibung |
|---|---|
| Immer Exception handeln | SCM-Proxys können verschiedene Exceptions werfen |
| Timeouts konfigurieren | Im Communication Arrangement passende Werte setzen |
| Retry nur bei transient errors | Timeouts ja, 4xx-Fehler nein |
| Logging aktivieren | API-Aufrufe protokollieren für Debugging |
| Credentials nie hardcoden | Communication Arrangements nutzen |
| API-Version beachten | Bei Proxy-Regenerierung auf Breaking Changes achten |
SCM in RAP integrieren
Custom Entity für externe Daten
Wenn du externe API-Daten in einer Fiori-App anzeigen willst:
" CDS Custom Entity definieren@EndUserText.label: 'Externe Wetterdaten'@ObjectModel.query.implementedBy: 'ABAP:ZCL_WEATHER_QUERY'define custom entity ZI_WeatherData{ key Location : abap.char(100); Temperature : abap.dec(5,2); Humidity : abap.int4; Description : abap.char(200); LastUpdated : abap.timestampl;}
" Query-Implementierung mit SCMCLASS zcl_weather_query DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_rap_query_provider.ENDCLASS.
CLASS zcl_weather_query IMPLEMENTATION. METHOD if_rap_query_provider~select. " Filterparameter auslesen DATA(lt_filters) = io_request->get_filter( )->get_as_ranges( ).
" SCM-Proxy für API-Aufruf DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement( comm_scenario = 'Z_WEATHER_OUTBOUND' ).
DATA(lo_proxy) = NEW zscm_weather_api( lo_destination ).
" API aufrufen TRY. DATA(ls_weather) = lo_proxy->get_current_weather( VALUE #( q = 'Berlin' ) ).
" In Custom Entity-Format mappen DATA(lt_result) = VALUE ztt_weather_data( ( location = ls_weather-name temperature = ls_weather-main-temp humidity = ls_weather-main-humidity description = ls_weather-weather[ 1 ]-description lastupdated = utclong_current( ) ) ).
io_response->set_total_number_of_records( lines( lt_result ) ). io_response->set_data( lt_result ).
CATCH cx_root INTO DATA(lx_error). RAISE EXCEPTION TYPE zcx_rap_query_provider EXPORTING previous = lx_error. ENDTRY. ENDMETHOD.ENDCLASS.Für mehr Details zu externen APIs in RAP siehe RAP External API Consumption.
Häufige Fehler und Lösungen
Problem: “No metadata found”
Symptom: Proxy kann nicht erstellt werdenUrsache: EDMX/OpenAPI-Datei ist fehlerhaft oder unvollständig
Lösung:1. API-Spezifikation im Browser validieren (Swagger Editor)2. Fehlende Referenzen ($ref) prüfen3. Bei OpenAPI: Version 3.0+ erforderlichProblem: “Destination not found”
Symptom: Runtime-Fehler beim Proxy-AufrufUrsache: Communication Arrangement fehlt oder falsch konfiguriert
Lösung:1. Fiori App "Communication Arrangements" öffnen2. Scenario-ID prüfen (muss mit Code übereinstimmen)3. Status "Active" sicherstellen4. Service-ID im Code prüfen (service_id Parameter)Problem: “Type mismatch in response”
Symptom: Datentyp-Fehler beim Zugriff auf Response-FelderUrsache: API hat Schema geändert, aber Proxy wurde nicht aktualisiert
Lösung:1. Neue API-Spezifikation herunterladen2. SCM in ADT öffnen → Rechtsklick → "Update Service"3. Generierte Strukturen prüfen4. Aufrufenden Code anpassenWeiterführende Themen
- Communication Scenarios Guide - Destination-Konfiguration im Detail
- ABAP HTTP Client - Direkter API-Zugriff ohne SCM
- RAP External API Consumption - APIs in RAP-Anwendungen integrieren
- OAuth 2.0 / JWT in ABAP Cloud - Authentifizierung für externe APIs
- SOAP Web Services konsumieren - SCM für SOAP/WSDL
Fazit
Das Service Consumption Model ist der empfohlene Weg für die Integration stabiler externer APIs in ABAP Cloud. Die automatische Generierung von Proxy-Klassen und Datentypen spart Entwicklungszeit, erhöht die Codequalität und macht API-Änderungen sofort sichtbar. Für einfache oder dynamische Szenarien bleibt der direkte HTTP-Client eine valide Alternative.