ABAP HTTP Client: Calling REST APIs

Category
ABAP-Statements
Published
Author
Johannes

HTTP Clients enable communication with external REST APIs from ABAP. There are two main classes: CL_HTTP_CLIENT (classic) and CL_WEB_HTTP_CLIENT (modern/Cloud).

Overview

ClassAvailabilityRecommendation
CL_HTTP_CLIENTClassic ABAPOn-Premise
CL_WEB_HTTP_CLIENTABAP Cloud, from 7.54Cloud, new developments

CL_HTTP_CLIENT (Classic)

1. Simple GET Request

DATA: lo_client TYPE REF TO if_http_client,
lv_response TYPE string,
lv_code TYPE i.
" Create client
cl_http_client=>create_by_url(
EXPORTING
url = 'https://api.example.com/users'
IMPORTING
client = lo_client
).
" Send request
lo_client->send( ).
lo_client->receive( ).
" Read response
lv_code = lo_client->response->get_status( )-code.
lv_response = lo_client->response->get_cdata( ).
" Close connection
lo_client->close( ).
IF lv_code = 200.
WRITE: / 'Success:', lv_response.
ELSE.
WRITE: / 'Error:', lv_code.
ENDIF.

2. GET with Query Parameters

DATA: lo_client TYPE REF TO if_http_client,
lv_url TYPE string.
" URL with parameters
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
).
" Or set parameters individually
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 with JSON

DATA: lo_client TYPE REF TO if_http_client,
lv_json TYPE string.
" Create JSON body
lv_json = '{"name":"Max","email":"[email protected]"}'.
cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/users'
IMPORTING client = lo_client
).
" Set HTTP method
lo_client->request->set_method( if_http_request=>co_request_method_post ).
" Set Content-Type
lo_client->request->set_header_field(
name = 'Content-Type'
value = 'application/json'
).
" Set body
lo_client->request->set_cdata( lv_json ).
" Send
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: / 'Successfully created'.
WHEN 400.
WRITE: / 'Invalid request'.
WHEN 401.
WRITE: / 'Not authorized'.
WHEN OTHERS.
WRITE: / 'Error:', lv_status.
ENDCASE.

4. PUT Request (Update)

lv_json = '{"name":"Max Mustermann","email":"[email protected]"}'.
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: / 'Successfully deleted'.
ENDIF.

6. Basic Authentication

cl_http_client=>create_by_url(
EXPORTING url = 'https://api.example.com/secure'
IMPORTING client = lo_client
).
" Set Basic Auth
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
).
" Set Authorization Header
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 = 'en-US'
).

9. Set Timeout

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

10. SSL/HTTPS Certificates

" For self-signed certificates
lo_client->propertytype_accept_cookie = if_http_client=>co_enabled.
" SSL client certificate (STRUST)
lo_client->set_ssl_id( 'ANONYM' ). " Or PSE name
" Ignore SSL errors (FOR TESTING ONLY!)
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 from SM59 or 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( ).
" Set headers
lo_request->set_header_field(
i_name = 'Content-Type'
i_value = 'application/json'
).
" Set body
lo_request->set_text( '{"name":"Max","email":"[email protected]"}' ).
" Execute POST
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. Using Destination from SM59

TRY.
" Use destination from SM59
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_MY_SCENARIO'
service_id = 'Z_MY_SERVICE'
).
" Or directly by 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.

Practical Examples

14. Complete 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( ).
" Parse JSON
/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.
" Usage
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 = '[email protected]' )
).
CATCH cx_web_http_client_error INTO DATA(lx_error).
WRITE: / lx_error->get_text( ).
ENDTRY.

15. Error Handling

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.
" Success
DATA(lv_data) = lo_client->response->get_cdata( ).
WHEN 400.
" Bad Request
DATA(lv_error) = lo_client->response->get_cdata( ).
WRITE: / 'Invalid request:', lv_error.
WHEN 401.
WRITE: / 'Authentication failed'.
WHEN 403.
WRITE: / 'Access denied'.
WHEN 404.
WRITE: / 'Resource not found'.
WHEN 500.
WRITE: / 'Server error'.
WHEN OTHERS.
WRITE: / 'HTTP Status:', lv_status-code, lv_status-reason.
ENDCASE.
CATCH cx_root INTO DATA(lx_error).
WRITE: / 'Error:', lx_error->get_text( ).
CLEANUP.
IF lo_client IS BOUND.
lo_client->close( ).
ENDIF.
ENDTRY.

16. Sending Binary Data (Files)

DATA: lv_file_content TYPE xstring.
" File as binary data
lv_file_content = '...'. " e.g. from file or table
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 ).

Important Notes / Best Practices

  • Use CL_WEB_HTTP_CLIENT for ABAP Cloud and new developments.
  • Always call close() - even on errors (TRY-FINALLY).
  • Use Destinations (SM59) for configurable endpoints.
  • Set Timeouts for slow external APIs.
  • Import SSL certificates in STRUST for HTTPS.
  • Use /ui2/cl_json to serialize/deserialize JSON.
  • Evaluate HTTP status codes for error handling.
  • Don’t hardcode API keys/tokens in code - use destinations.
  • Implement logging for debugging.
  • Consider proxy settings in production systems.