ABAP HTTP Client: REST-APIs aufrufen

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

HTTP-Clients ermöglichen die Kommunikation mit externen REST-APIs aus ABAP. Es gibt zwei Hauptklassen: CL_HTTP_CLIENT (klassisch) und CL_WEB_HTTP_CLIENT (modern/Cloud).

Übersicht

KlasseVerfügbarkeitEmpfehlung
CL_HTTP_CLIENTKlassisches ABAPOn-Premise
CL_WEB_HTTP_CLIENTABAP Cloud, ab 7.54Cloud, neue Entwicklungen

CL_HTTP_CLIENT (Klassisch)

1. Einfacher GET-Request

DATA: lo_client TYPE REF TO if_http_client,
lv_response TYPE string,
lv_code TYPE i.
" Client erstellen
cl_http_client=>create_by_url(
EXPORTING
url = 'https://api.example.com/users'
IMPORTING
client = lo_client
).
" Request senden
lo_client->send( ).
lo_client->receive( ).
" Response lesen
lv_code = lo_client->response->get_status( )-code.
lv_response = lo_client->response->get_cdata( ).
" Verbindung schließen
lo_client->close( ).
IF lv_code = 200.
WRITE: / 'Erfolg:', lv_response.
ELSE.
WRITE: / 'Fehler:', lv_code.
ENDIF.

2. GET mit Query-Parametern

DATA: lo_client TYPE REF TO if_http_client,
lv_url TYPE string.
" URL mit Parametern
lv_url = 'https://api.example.com/users?status=active&limit=10'.
cl_http_client=>create_by_url(
EXPORTING url = lv_url
IMPORTING client = lo_client
).
" Oder Parameter einzeln setzen
lo_client->request->set_form_field(
name = 'status'
value = 'active'
).
lo_client->send( ).
lo_client->receive( ).
DATA(lv_response) = lo_client->response->get_cdata( ).
lo_client->close( ).

3. POST-Request mit JSON

DATA: lo_client TYPE REF TO if_http_client,
lv_json TYPE string.
" JSON-Body erstellen
lv_json = '{"name":"Max","email":"max@example.com"}'.
cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/users'
IMPORTING client = lo_client
).
" HTTP-Methode setzen
lo_client->request->set_method( if_http_request=>co_request_method_post ).
" Content-Type setzen
lo_client->request->set_header_field(
name = 'Content-Type'
value = 'application/json'
).
" Body setzen
lo_client->request->set_cdata( lv_json ).
" Senden
lo_client->send( ).
lo_client->receive( ).
DATA(lv_status) = lo_client->response->get_status( )-code.
DATA(lv_response) = lo_client->response->get_cdata( ).
lo_client->close( ).
CASE lv_status.
WHEN 200 OR 201.
WRITE: / 'Erfolgreich erstellt'.
WHEN 400.
WRITE: / 'Ungültige Anfrage'.
WHEN 401.
WRITE: / 'Nicht autorisiert'.
WHEN OTHERS.
WRITE: / 'Fehler:', lv_status.
ENDCASE.

4. PUT-Request (Update)

lv_json = '{"name":"Max Mustermann","email":"max.m@example.com"}'.
cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/users/123'
IMPORTING client = lo_client
).
lo_client->request->set_method( if_http_request=>co_request_method_put ).
lo_client->request->set_header_field(
name = 'Content-Type'
value = 'application/json'
).
lo_client->request->set_cdata( lv_json ).
lo_client->send( ).
lo_client->receive( ).
lo_client->close( ).

5. DELETE-Request

cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/users/123'
IMPORTING client = lo_client
).
lo_client->request->set_method( if_http_request=>co_request_method_delete ).
lo_client->send( ).
lo_client->receive( ).
DATA(lv_status) = lo_client->response->get_status( )-code.
lo_client->close( ).
IF lv_status = 204 OR lv_status = 200.
WRITE: / 'Erfolgreich gelöscht'.
ENDIF.

6. Basic Authentication

cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/secure'
IMPORTING client = lo_client
).
" Basic Auth setzen
lo_client->authenticate(
username = 'myuser'
password = 'mypassword'
).
lo_client->send( ).
lo_client->receive( ).
lo_client->close( ).

7. Bearer Token (OAuth)

DATA: lv_token TYPE string VALUE 'eyJhbGciOiJIUzI1NiIs...'.
cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/protected'
IMPORTING client = lo_client
).
" Authorization Header setzen
lo_client->request->set_header_field(
name = 'Authorization'
value = |Bearer { lv_token }|
).
lo_client->send( ).
lo_client->receive( ).
lo_client->close( ).

8. Custom Headers

lo_client->request->set_header_field(
name = 'X-API-Key'
value = 'my-api-key-12345'
).
lo_client->request->set_header_field(
name = 'Accept'
value = 'application/json'
).
lo_client->request->set_header_field(
name = 'Accept-Language'
value = 'de-DE'
).

9. Timeout setzen

cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/slow'
IMPORTING client = lo_client
).
" Timeout in Sekunden
lo_client->send( timeout = 30 ).
lo_client->receive( timeout = 30 ).

10. SSL/HTTPS-Zertifikate

" Für Self-Signed Zertifikate
lo_client->propertytype_accept_cookie = if_http_client=>co_enabled.
" SSL-Client-Zertifikat (STRUST)
lo_client->set_ssl_id( 'ANONYM' ). " Oder PSE-Name
" SSL-Fehler ignorieren (NUR FÜR TESTS!)
lo_client->propertytype_logon_popup = if_http_client=>co_disabled.

CL_WEB_HTTP_CLIENT (Modern/Cloud)

11. GET-Request (Cloud)

DATA: lo_client TYPE REF TO if_web_http_client,
lo_response TYPE REF TO if_web_http_response.
TRY.
" Destination aus SM59 oder HTTP-URL
DATA(lo_destination) = cl_http_destination_provider=>create_by_url(
i_url = 'https://api.example.com/users'
).
lo_client = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
lo_response = lo_client->execute( if_web_http_client=>get ).
DATA(lv_status) = lo_response->get_status( )-code.
DATA(lv_body) = lo_response->get_text( ).
lo_client->close( ).
CATCH cx_web_http_client_error INTO DATA(lx_error).
WRITE: / 'HTTP Error:', lx_error->get_text( ).
CATCH cx_http_dest_provider_error INTO DATA(lx_dest).
WRITE: / 'Destination Error:', lx_dest->get_text( ).
ENDTRY.

12. POST-Request (Cloud)

TRY.
DATA(lo_destination) = cl_http_destination_provider=>create_by_url(
i_url = 'https://api.example.com/users'
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
DATA(lo_request) = lo_client->get_http_request( ).
" Headers setzen
lo_request->set_header_field(
i_name = 'Content-Type'
i_value = 'application/json'
).
" Body setzen
lo_request->set_text( '{"name":"Max","email":"max@example.com"}' ).
" POST ausführen
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
DATA(lv_status) = lo_response->get_status( )-code.
DATA(lv_body) = lo_response->get_text( ).
lo_client->close( ).
CATCH cx_web_http_client_error cx_http_dest_provider_error INTO DATA(lx_error).
WRITE: / lx_error->get_text( ).
ENDTRY.

13. Mit Destination aus SM59

TRY.
" Destination aus SM59 verwenden
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_MY_SCENARIO'
service_id = 'Z_MY_SERVICE'
).
" Oder direkt per Name
DATA(lo_dest_by_name) = cl_http_destination_provider=>create_by_cloud_destination(
i_name = 'MY_DESTINATION'
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
" ...
CATCH cx_http_dest_provider_error INTO DATA(lx_error).
WRITE: / lx_error->get_text( ).
ENDTRY.

Praktische Beispiele

14. Kompletter REST-Client

CLASS zcl_api_client DEFINITION PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_user,
id TYPE i,
name TYPE string,
email TYPE string,
END OF ty_user,
ty_users TYPE TABLE OF ty_user WITH EMPTY KEY.
METHODS: constructor
IMPORTING iv_base_url TYPE string
iv_api_key TYPE string OPTIONAL.
METHODS: get_users
RETURNING VALUE(rt_users) TYPE ty_users
RAISING cx_web_http_client_error.
METHODS: create_user
IMPORTING is_user TYPE ty_user
RETURNING VALUE(rs_user) TYPE ty_user
RAISING cx_web_http_client_error.
PRIVATE SECTION.
DATA: mv_base_url TYPE string,
mv_api_key TYPE string.
METHODS: create_client
RETURNING VALUE(ro_client) TYPE REF TO if_http_client.
ENDCLASS.
CLASS zcl_api_client IMPLEMENTATION.
METHOD constructor.
mv_base_url = iv_base_url.
mv_api_key = iv_api_key.
ENDMETHOD.
METHOD create_client.
cl_http_client=>create_by_url(
EXPORTING url = mv_base_url
IMPORTING client = ro_client
).
IF mv_api_key IS NOT INITIAL.
ro_client->request->set_header_field(
name = 'X-API-Key'
value = mv_api_key
).
ENDIF.
ro_client->request->set_header_field(
name = 'Accept'
value = 'application/json'
).
ENDMETHOD.
METHOD get_users.
DATA(lo_client) = create_client( ).
lo_client->request->set_uri_path( '/users' ).
lo_client->send( ).
lo_client->receive( ).
DATA(lv_response) = lo_client->response->get_cdata( ).
lo_client->close( ).
" JSON parsen
/ui2/cl_json=>deserialize(
EXPORTING json = lv_response
CHANGING data = rt_users
).
ENDMETHOD.
METHOD create_user.
DATA(lo_client) = create_client( ).
lo_client->request->set_uri_path( '/users' ).
lo_client->request->set_method( if_http_request=>co_request_method_post ).
lo_client->request->set_header_field(
name = 'Content-Type'
value = 'application/json'
).
DATA(lv_json) = /ui2/cl_json=>serialize( data = is_user ).
lo_client->request->set_cdata( lv_json ).
lo_client->send( ).
lo_client->receive( ).
DATA(lv_response) = lo_client->response->get_cdata( ).
lo_client->close( ).
/ui2/cl_json=>deserialize(
EXPORTING json = lv_response
CHANGING data = rs_user
).
ENDMETHOD.
ENDCLASS.
" Verwendung
DATA(lo_api) = NEW zcl_api_client(
iv_base_url = 'https://api.example.com'
iv_api_key = 'my-key'
).
TRY.
DATA(lt_users) = lo_api->get_users( ).
DATA(ls_new_user) = lo_api->create_user(
is_user = VALUE #( name = 'Test' email = 'test@test.de' )
).
CATCH cx_web_http_client_error INTO DATA(lx_error).
WRITE: / lx_error->get_text( ).
ENDTRY.

15. Fehlerbehandlung

TRY.
cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com'
IMPORTING client = lo_client
).
lo_client->send( ).
lo_client->receive( ).
DATA(lv_status) = lo_client->response->get_status( ).
CASE lv_status-code.
WHEN 200.
" Erfolg
DATA(lv_data) = lo_client->response->get_cdata( ).
WHEN 400.
" Bad Request
DATA(lv_error) = lo_client->response->get_cdata( ).
WRITE: / 'Ungültige Anfrage:', lv_error.
WHEN 401.
WRITE: / 'Authentifizierung fehlgeschlagen'.
WHEN 403.
WRITE: / 'Zugriff verweigert'.
WHEN 404.
WRITE: / 'Ressource nicht gefunden'.
WHEN 500.
WRITE: / 'Server-Fehler'.
WHEN OTHERS.
WRITE: / 'HTTP-Status:', lv_status-code, lv_status-reason.
ENDCASE.
CATCH cx_root INTO DATA(lx_error).
WRITE: / 'Fehler:', lx_error->get_text( ).
CLEANUP.
IF lo_client IS BOUND.
lo_client->close( ).
ENDIF.
ENDTRY.

16. Binärdaten (Dateien) senden

DATA: lv_file_content TYPE xstring.
" Datei als Binärdaten
lv_file_content = '...'. " z.B. aus Datei oder Tabelle
lo_client->request->set_method( if_http_request=>co_request_method_post ).
lo_client->request->set_header_field(
name = 'Content-Type'
value = 'application/octet-stream'
).
lo_client->request->set_data( lv_file_content ).
lo_client->send( ).
lo_client->receive( ).

17. Multipart/Form-Data

DATA: lv_boundary TYPE string VALUE '----WebKitFormBoundary7MA4YWxk'.
lo_client->request->set_header_field(
name = 'Content-Type'
value = |multipart/form-data; boundary={ lv_boundary }|
).
DATA(lv_body) = |--{ lv_boundary }\r\n| &&
|Content-Disposition: form-data; name="field1"\r\n\r\n| &&
|value1\r\n| &&
|--{ lv_boundary }\r\n| &&
|Content-Disposition: form-data; name="file"; filename="test.txt"\r\n| &&
|Content-Type: text/plain\r\n\r\n| &&
|File content here\r\n| &&
|--{ lv_boundary }--\r\n|.
lo_client->request->set_cdata( lv_body ).

Wichtige Hinweise / Best Practice

  • CL_WEB_HTTP_CLIENT für ABAP Cloud und neue Entwicklungen.
  • Immer close() aufrufen – auch bei Fehlern (TRY-FINALLY).
  • Destination (SM59) für konfigurierbare Endpoints verwenden.
  • Timeouts setzen für langsame externe APIs.
  • SSL-Zertifikate in STRUST importieren für HTTPS.
  • JSON mit /ui2/cl_json serialisieren/deserialisieren.
  • HTTP-Status-Codes auswerten für Fehlerbehandlung.
  • API-Keys/Tokens nicht im Code hardcoden – Destinations nutzen.
  • Logging für Debugging implementieren.
  • Beachten Sie Proxy-Einstellungen in Produktivsystemen.