Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

changing the url of a destination wich is managed in the transaction SM59

h3n
Participant
0 Kudos

Hi,

I am calling a Website in ABAP with some lines of code. The initial call will be this:

CALL METHOD cl_http_client=>create_by_destination
EXPORTING
destination = <destination in SM59>
IMPORTING
client = l_client

After this I want to modify the URL of the Call.

I tried to modify the Destination with
cl_http_utility=>set_request_uri( request = l_client->request uri = '/test/')
but the new URL will be ignored.

Is it possible to make a call different of the destination which is managed in SM59?

Regards
Henning

1 ACCEPTED SOLUTION

Sandra_Rossi
Active Contributor
0 Kudos

Just read the URL from SM59 (RFC_READ_HTTP_DESTINATION), and create HTTP client (cl_http_client=>create_by_url( EXPORTING url = 'http://...' ))

EDIT 2023: I realize that my answer in 2017 wasn't the best one...

The RFC destination should mention the domain only, without any path behind the domain.

Then you can use cl_http_utility=>set_request_uri( request = l_client->request uri = '/test/') or whatever URI you want.

The RFC destination may indicate a path after a domain, but it means that the URI in set_request_uri will be appended to this path.

8 REPLIES 8

Sandra_Rossi
Active Contributor
0 Kudos

Just read the URL from SM59 (RFC_READ_HTTP_DESTINATION), and create HTTP client (cl_http_client=>create_by_url( EXPORTING url = 'http://...' ))

EDIT 2023: I realize that my answer in 2017 wasn't the best one...

The RFC destination should mention the domain only, without any path behind the domain.

Then you can use cl_http_utility=>set_request_uri( request = l_client->request uri = '/test/') or whatever URI you want.

The RFC destination may indicate a path after a domain, but it means that the URI in set_request_uri will be appended to this path.

0 Kudos

Old post and old answer. This solution will do! But looking for a more optimized solution. I am using a CL_REST_HTTP_CLIENT which is (sequentially) called within one session on different URL's. I would like to prevent creating different clients for each different URL.

0 Kudos

jack.graus2 Please ask a new question (NB: in that question, I'd like to know your motivation to reuse the same client instance for different URLs...)

0 Kudos

Hello, I am calling a Cloud service that requires several call operations in sequence. The host for each of these calls is same. The only difference is a different URL holding paramaters for the call operation. The question is: Is it possible to open and close the HTTP connection only once? This to prevent opening and closing the (same) HTTP connection several times. Just by switching the URL in between the subsequent calls.

0 Kudos

jack.graus2 Nobody does that, nobody can do that (as far as I know). Open/close is the technical implementation of sending an HTTP request and waiting for the response. You didn't explain why you want to do that. Just "because"?

0 Kudos

jack.graus2 I realize that my answer in 2017 wasn't the best one...

The RFC destination should mention the domain only, without any path behind the domain.

Then you can use cl_http_utility=>set_request_uri( request = l_client->request uri = '/test/') or whatever URI you want.

The RFC destination may indicate a path, but it means that the URI in set_request_uri will be appended to this path.

Thank you, your answer helped me to include that URL part in a small REST client. I realize a HTTP connection could be opened and closed for each REST request that is send to the HTTP client.

The REST API I use now make it possible to send several operations to the same HTTP client. This to avoid opening and closing the HTTP connection for each request operation. But mainly also to handle cookie. The REST API does hide the cookie handling from the application and is included in the REST API.

Please fine below the source code. It might be useful for someone.

Class definition:

*"* use this source file for any type of declarations (class
*"* definitions, interfaces or type declarations) you need for
*"* components in the private section

CLASS lcl_rest_client DEFINITION CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ts_authorize,
rfcdest TYPE rfcdest,
key TYPE sysuuid_c,
user TYPE string,
password TYPE string,
END OF ts_authorize.

INTERFACES if_rest_client .

METHODS:
constructor
IMPORTING
is_authorize TYPE ts_authorize,

get
IMPORTING
iv_path TYPE string
RETURNING
VALUE(ro_entity) TYPE REF TO if_rest_entity,

post
IMPORTING
iv_path TYPE string
iv_data TYPE xstring
RETURNING
VALUE(ro_entity) TYPE REF TO if_rest_entity.

ALIASES:
get_status FOR if_rest_client~get_status,
close FOR if_rest_client~close,
get_response_entity FOR if_rest_client~get_response_entity.

PRIVATE SECTION.
DATA:
go_http_client TYPE REF TO if_http_client,
go_rest_client TYPE REF TO if_rest_client,
go_rest_entity TYPE REF TO if_rest_entity,
gv_authorize TYPE xstring,
gv_cookie TYPE string,
gv_path TYPE string,
gr_data TYPE REF TO xstring,
gv_retry TYPE i VALUE 1.

METHODS:
send_receive
IMPORTING
iv_http_method TYPE string
io_entity TYPE REF TO if_rest_entity OPTIONAL,

set_request_uri
IMPORTING
iv_path TYPE string.
ENDCLASS.

Class implementation:

*"* use this source file for the definition and implementation of
*"* local helper classes, interface definitions and type
*"* declarations

CLASS lcl_rest_client IMPLEMENTATION.
METHOD constructor.
DATA:
lo_writer TYPE REF TO cl_sxml_string_writer.

* HTTP client
cl_http_client=>create_by_destination(
EXPORTING
destination = is_authorize-rfcdest
IMPORTING
client = go_http_client
EXCEPTIONS
argument_not_found = 1
destination_not_found = 2
destination_no_authority = 3
plugin_not_active = 4
internal_error = 5
OTHERS = 6 ).
IF syst-subrc NE 0.
RAISE EXCEPTION TYPE cx_rest_client_exception EXPORTING textid = cx_rest_client_exception=>http_client_creation_failed.
ENDIF.

go_http_client->propertytype_logon_popup = if_http_client=>co_disabled.

* Rest client
go_rest_client = CAST #( NEW cl_rest_http_client( go_http_client ) ).
go_rest_entity = go_rest_client->create_request_entity( ).
go_rest_entity->set_content_type( if_rest_media_type=>gc_appl_json ).
go_rest_entity->set_content_compression( abap_true ).
go_rest_entity->set_header_fields( VALUE #(
( name = `x-rs-culture` value = `en-US` )
( name = `x-rs-uiculture` value = `en-US` )
( name = `x-rs-version` value = `2011-10-14` )
( name = `x-rs-key` value = is_authorize-key )
( name = `Connection` value = `Close` ) ) ) ##NO_TEXT.

* Authentication
lo_writer = cl_sxml_string_writer=>create( if_sxml=>co_xt_json ).
CALL TRANSFORMATION zmr1m_readsoft_authenticate SOURCE authorize = is_authorize RESULT XML lo_writer.
gv_authorize = lo_writer->get_output( abap_false ).
ENDMETHOD.

METHOD get.
gv_path = iv_path.
CLEAR gr_data.
if_rest_client~get( ).
CHECK ro_entity IS SUPPLIED.
ro_entity = go_rest_client->get_response_entity( ).
ENDMETHOD.

METHOD post.
gv_path = iv_path.
gr_data = REF #( iv_data ).
if_rest_client~post( go_rest_entity ).
CHECK ro_entity IS SUPPLIED.
ro_entity = go_rest_client->get_response_entity( ).
ENDMETHOD.

METHOD if_rest_client~head.
send_receive( if_rest_message=>gc_method_head ).
ENDMETHOD.

METHOD if_rest_client~get.
send_receive( if_rest_message=>gc_method_get ).
ENDMETHOD.

METHOD if_rest_client~delete.
send_receive( if_rest_message=>gc_method_delete ).
ENDMETHOD.

METHOD if_rest_client~options.
send_receive( if_rest_message=>gc_method_options ).
ENDMETHOD.

METHOD if_rest_client~post.
send_receive( iv_http_method = if_rest_message=>gc_method_post io_entity = io_entity ).
ENDMETHOD.

METHOD if_rest_client~put.
send_receive( if_rest_message=>gc_method_put ).
ENDMETHOD.

METHOD if_rest_client~get_status.
rv_status = go_rest_client->get_status( ).
ENDMETHOD.

METHOD if_rest_client~close.
go_rest_client->close( ).
ENDMETHOD.

METHOD if_rest_client~get_response_entity.
ro_response_entity = go_rest_client->get_response_entity( ).
ENDMETHOD.

METHOD send_receive.
DATA:
lo_rest_exception TYPE REF TO cx_rest_exception,
lt_header TYPE tihttpnvp.

TRY.
IF gv_cookie IS INITIAL.
RAISE EXCEPTION TYPE cx_rest_exception EXPORTING status_code = cl_rest_status_code=>gc_client_error_unauthorized.
ENDIF.

go_rest_entity->set_header_field( iv_name = `Cookie` iv_value = gv_cookie ) ##NO_TEXT.
set_request_uri( gv_path ).
go_rest_entity->set_binary_data( SWITCH #( iv_http_method WHEN if_rest_message=>gc_method_post OR if_rest_message=>gc_method_put THEN gr_data->* ELSE `` ) ).

CASE iv_http_method.
WHEN if_rest_message=>gc_method_head.
go_rest_client->head( ).
WHEN if_rest_message=>gc_method_get.
go_rest_client->get( ).
WHEN if_rest_message=>gc_method_delete.
go_rest_client->head( ).
WHEN if_rest_message=>gc_method_options.
go_rest_client->options( ).
WHEN if_rest_message=>gc_method_post.
go_rest_client->post( io_entity ).
WHEN if_rest_message=>gc_method_put.
go_rest_client->options( ).
ENDCASE.

CATCH cx_rest_exception INTO lo_rest_exception.
CASE lo_rest_exception->status_code.
WHEN cl_rest_status_code=>gc_client_error_unauthorized.
gv_retry = gv_retry - 1.
IF gv_retry LT 0.
RAISE EXCEPTION TYPE cx_rest_exception EXPORTING previous = lo_rest_exception status_code = cl_rest_status_code=>gc_client_error_unauthorized.
ELSE.
set_request_uri( `authentication/rest/authenticate` ).
go_rest_entity->set_binary_data( gv_authorize ).
go_rest_client->post( go_rest_entity ).
lt_header = go_rest_client->get_response_entity( )->get_header_fields( ).
gv_cookie = VALUE #( lt_header[ name = `set-cookie` ]-value OPTIONAL ).
RETRY.
ENDIF.

WHEN OTHERS.
RAISE EXCEPTION TYPE cx_rest_exception EXPORTING previous = lo_rest_exception status_code = go_rest_client->get_status( ).
ENDCASE.
ENDTRY.
ENDMETHOD.

METHOD set_request_uri.
cl_http_utility=>set_request_uri(
request = go_http_client->request
uri = go_http_client->create_rel_url( path = iv_path ) ).
ENDMETHOD.
ENDCLASS.

0 Kudos

jack.graus2 Interesting to see that send/receive can be used multiple times between open and close. I tried to understand what could be the benefit of "keeping alive" and reusing the HTTP connections: I searched the Web at "http handshake keep alive site:stackoverflow.com" (below threads for instance). In your case, are you sure that the HTTP connection is reused? How do you measure the benefit? (if any) Note that you are using "connection: close", shouldn't it be "connection: keep-alive"? I guess that "connection: close" says to close the connection after receive. Notes: I saw in the Web that the server may ignore "connection: keep-alive"; HTTP/2 default is to version used (1.x versus 2).

My 2 cents: it's interesting to work on improvement only if you can measure the benefit.

HTTP-Long Polling keep-alive and handshakes - Stack Overflow

https - Multiple SSL/TLS handshakes despite Keep-Alive and Session Identifier/Ticket enabled - Stack...

How long the connection will be kept alive in Http/2? - Stack Overflow