Consume Odata Service in ABAP CL_HTTP_CLIENT->CREATE_BY_DESTINATION
This blog would have not been possible, but for the awesome community that is SCN. I would like to thank every contributor ever for helping me out in my hours of need!.
I had tremendous help in navigating through my current requirement thanks to the below blog posts.
How to consume an OData service using OData Services Consumption and Integration (OSCI)
Thank you. Andre Fischer
Consuming an External RESTful Web Service with ABAP in Gateway
both these blogs helped me understand the intricacies of the functionality that is Consuming an OData Service.
this Blog can be considered as an extension of the Blog by Paul J. Modderman.
we can consume a data service by using the method CREATE_BY_URL of the class CL_HTTP_CLIENT, but when authentication is involved this method was ill suited for it.
The CREATE_BY_DESTINATION method however enables us to store the Credentials in a more standard and secured fashion.
The Requirement:-
I needed to access an OData service that was exposed by HANA . It is required that we trigger this service from the ECC system and process the result.
The user would be logging in to ECC directly and not via portal, thus it would require the use of an RFC destination Login Credentials.
The Process:-
Step 1.
we have to create the RFC connection in SM59 as below.
- Go to TCode SM59
- Click on the create new connection button.
- Provide the description
- Choose the connection type as G.
- enter the Host name/port number(an Odata Service generally has a URL containing “.COM” followed by “:” Port Number)
- The part until the “.com” without the HTTP:// is the host name
- The part after the “:” is the port number
- Enter any proxy details if a proxy is being used(we were not in my case)
- go to the Logon & Security tab
- CHoose the Basic Authentication Radio Button.
- Enter the logon credentials
- Save and click on connection test.
- If all setting are proper you should be able to see a webapage that is relevant to the Host you entered, in the Response Body/Response Text tabs.
Step2.
Now that we have created the RFC connection we proceed to the creation of the HTTP client .
to create the client we use the attached code. CL_HTTP_CLIENT.txt.
DATA: lo_http_client TYPE REF TO if_http_client,
lv_service TYPE string,
lv_result TYPE string.
“xml variables
DATA: lo_ixml TYPE REF TO if_ixml,
lo_streamfactory TYPE REF TO if_ixml_stream_factory,
lo_istream TYPE REF TO if_ixml_istream,
lo_document TYPE REF TO if_ixml_document,
lo_parser TYPE REF TO if_ixml_parser,
lo_weather_element TYPE REF TO if_ixml_element,
lo_weather_nodes TYPE REF TO if_ixml_node_list,
lo_curr_node TYPE REF TO if_ixml_node,
lv_value TYPE string,
lv_node_length TYPE i,
lv_node_index TYPE i,
lv_node_name TYPE string,
lv_node_value TYPE string.
************************************************************************
* lv_ destination will be name of the RFC destination we created in SM59
************************************************************************
CALL METHOD cl_http_client=>create_by_destination
EXPORTING
destination = lv_destination
IMPORTING
client = lo_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 sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
*************************************************************************************************
* we need to build the URI, this is the part in the OData Service that comes after the port number
* This includes the Path and Query string for the service that is being called on the host.
* lv_uri holds the path and query string
*************************************************************************************************
CALL METHOD cl_http_utility=>set_request_uri
EXPORTING
request = lo_http_client->request
uri = lv_uri.
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
**************************************************
* Making sense of the result parsing the XML
**************************************************
lv_result = lo_http_client->response->get_cdata( ).
lo_ixml = cl_ixml=>create( ).
lo_streamfactory = lo_ixml->create_stream_factory( ).
lo_istream = lo_streamfactory->create_istream_string(
lv_result ).
lo_document = lo_ixml->create_document( ).
lo_parser = lo_ixml->create_parser(
stream_factory = lo_streamfactory
istream = lo_istream
document = lo_document ).
“This actually makes the XML document navigable
lo_parser->parse( ).
DATA: lv_name TYPE string.
“Navigate XML to nodes we want to process
*lo_weather_element = lo_document->get_root_element( ).
lv_name = ‘content’.
lo_weather_element = lo_document->find_from_name( lv_name ).
lo_weather_nodes = lo_weather_element->get_children( ).
“Move through the nodes and assign appropriate values to export
lv_node_length = lo_weather_nodes->get_length( ).
lv_node_index = 0.
WHILE lv_node_index < lv_node_length.
lo_curr_node = lo_weather_nodes->get_item( lv_node_index ).
lv_node_name = lo_curr_node->get_name( ).
lv_node_value = lo_curr_node->get_value( ).
ADD 1 TO lv_node_index.
ENDWHILE.
Hope this Helps!, let me know if i can clarify further.
Peace!!!!
Hi Vamsi,
Why not use the existing Gateway classes for OSCI integration?
You can call:
/iwfnd/cl_sutil_client_proxy=>get_instance( )->web_request(
EXPORTING
it_request_header = VALUE /iwfnd/sutil_property_t(
(
name = if_http_header_fields_sap=>request_method
value = if_http_entity=>co_request_method_get
) (
name = if_http_header_fields_sap=>request_uri
value = |{ mv_service_url }/{ iv_query }|
)
)
IMPORTING
ev_status_code = DATA(lv_status_code)
ev_response_body = rv_xbody
ev_error_text = DATA(lv_error_text)
).
To get the content, and then:
/iwfnd/cl_sutil_odata_mapper=>get_instance( )->convert_to_abap(
EXPORTING
iv_xdoc = http_get( |{ iv_entityset_name }| )
IMPORTING
ed_data = et_data
ev_error_text = DATA(lv_error_text) ).
To convert directly to the appropriate ABAP type (this also works with ComplexTypes).
But why do you want to consume an OData service in ABAP?
BR,
Tudor
Hi Tudor,
i am calling the HANA service from ECC.
In our landscape, the Gateway and ECC are different systems.
and the Class that you mentioned is only available in the gateway system.
that is why I am using the CL_HTTP_CLIENT class.
Many thanks,
Vamsi
Hi Vamsi,
Quick question and clarification required.
You mean i can consume odata service URL generated from HANA DB in ECC or BI System ?
-Amol S
Hi Amol,
Yes, it is possible. I am not sure if we can do it from BI, because i have no experience in that area. but from ECC ABAP definitely yes.
We are basically instantiating an HTTP Client and triggering the services.
Kind Regards,
Vamsi
Hi Tudor. Is web_request should be used only to simulate request? If no - how propertytype_logon_popup can be avoided?
Hi Tudor
How can token details be passed along with other client info at the time of the call, using the /iwfnd/cl_sutil_client_proxy=>get_instance( )->web_request.
Hi Manoj,
I haven't worked with this in a while, but as far as I can see in the method signtuare, you could use parameter IT_REQUEST_HEADER. Which kind of token are you using? I image something like
( name = if_http_header_fields=>authorization value = |Bearer { <your_token> }| )
Hope this helps!
Hi Tudor
The details used below need to be passed when the service is requested in ABAP.
Hi Manoj,
Yes, and each one of them corresponds to a header parameter. If you switch to the Headers tab in Postman you will see the technical names of the header fields as well.
I got an error when I use to access the way mentioned above(I tried both from Tudor and Vamsi). I have both Gateway and ECC in same system.
HTTP Receive failed: SSL handshake with iotmmsXXXXXXtrial.hanatrial.ondemand.com:443 failed: SSSLERR_PEER_CERT_UNTRUSTED (-102)#The peer's X.509 Certificate (chain) is untrusted##SapSSLSessionStart()==SSSLERR_PEER_CERT_UNTRUSTED# SSL:SSL_connnect() fail...
-------------------
Any idea what I am missing?
Hi Harikrishnan,
Your HTTP request is being rejected by the server you want to access. My basis team was able to help me out with this issue. a security certificate has to be downloaded from your target system and installed on the system from which you are trying to access the service using the transaction code STRUST
Since the error message mentions x.509 certificates, i am assuming that you are not using a user Id based authentication.
Try configuring your RFC connection using a User ID based authentication.
I shall try to look into the certificate based error and get back to you in the meanwhile.
Kind Regards,
Vamsi
Getting same error even after changing to Basic Authentication with user/password 😐 .
I am getting HTTP_INVALID_STATE exception while lo_http_client->receive().
have you tested your RFC connection? is the connection test succesful from SM59?
Hi Vamsi,
I am getting the same error as Invalid State with sy-subrc = 2 during call lo_http_client->receive .
I checked my RFC connection and it's status is OK.
My requirement is to consume one OData service from one ERP system to another ERP system through ABAP.
Very good post. Congratulations!
Matt Harding I think you will like this blog 😉
Hello Vamsi
Its really a nice post. I am trying the same with HCP. In HCP I have exposed a OData and trying to consume the OData from ABAP program.
I was getting http_invalid_state exception from receive method.
I have resolved it by adding Send method before the receive method call.
Now I'm not getting any error , but not receiving any XML also.
For the configuration part -
My SM59 config is working fine and im getting the connection successful .
Not sure about ICM configuration but our network team confirmed that there no block from firewall side.
Could you please help me out to identify the probable problem.
Thanks
Sudip
HI Sudip not sure if you are still facing the issue, but please let me know, if you can share your code here, i could help out.
Kind Regards
Vamsi
Hi Vamsi,
While trying to create the RFC Destination I am getting below error. I want to create Destination for my OData created in HCP for Iot services. Please suggest how to create successful connection.
Error - HTTPIO_PLG_CANCELED
O Data service -
https://iotmmsXXXXXXXXtrial.hanatrial.ondemand.com/com.sap.iotservices.mms/v1/api/http/app.svc/
Hi Yogendra,
i am not sure how HCP is configured, my experience is limited to ABAP. do check with your BASIS team they might be able to help.
Kind Regards,
Vamsi
Hi Vamsi,
Regarding connection type G, does the destination can be any Non-SAP system?
Or it can be any SAP system?
Any limitations for this destination?
Regards
Phani Poorna
Hi Phani,
In my case it as an SAP System. I created an RFC destination as we were required to access it from HANA.
you can create an RFC destination to your external system. or rather you can use the "Create_by_url" method also.
as shown here
Consuming an External RESTful Web Service with ABAP in Gateway
Kind Regards,
Vamsi
Hi Vamsi,
Thank you for the Info.
I am not familiar with that method. But if we use create_by_url method, how to authenticate the service?
Going forward if Single sign on is enabled then how it can help?
Kindly help me out
Regards
Phani Poorna
Hi Phani,
Even with create_by_url you can pass the requisite username and password as parameters in the method.
There are several methods in the class CL_HTTP_CLIENT that you can use for implementing "single sign on", "X-CSRF token" handling etc.
If you are implementing this on the Gateway Hub System Directly, there are other classes that are more easier to use.
These are referred to as OSCI.
this blog by Andre Fischer details the approach using OSCI.
How to consume an OData service using OData Services Consumption and Integration (OSCI)
By Andre Fischer
Kind Regards,
Vamsi
Good day Vamsi,
I thank you for this informative post. Please keep em coming 🙂
Will this blog still be relevant if I would like to POST data to the webservice?
With kind regards,
Sharif
HI,
Thanks for the blog
I am trying to use class CL_HTTP_CLIENT to trigger SAP cloud workflow from ABAP. I am able to get the CSRF token part successfully but the second POST call fails with HTTP 403 Forbidden error. where I am going wrong? I have posted the question already.
https://answers.sap.com/questions/615947/trigger-scp-from-abap-program.html
Dear Vamsi,
was referring to your link to call external Restful API in ABAP.
would appreciate your reply.
Thanks,
Ashish.
All outgoing and incoming requests are always tracked through the ICM.
You can use the SMICM transaction to check all traffic.
there is no SICF involved here. we are doing it dynamically in our class.
do correct me if you think otherwise.
HI Vamsi Krishna C V
I referred the code in the blog , but for me when I am calling the HANA service in the result it returning error Service exception: [258] insufficient privilege , I checked the RFC connection and its fine , from the browser also I am able to see the metadata of the service but not via ABAP , request your help.
(**--Get the response data
DATA(l_result) = lo_http_client->response->get_cdata( ).
I always get error below error
<?xml version="1.0" encoding="utf-8" standalone="yes"?><error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><code/><message xml:lang="en-US">Service exception: [258] insufficient privilege</message></error>
HI Rachit,
Apologies for the late reply, but have you checked if you are actually able to see the response from your service, when you do all the settings mentioned in Step 1?
If you are able to see the response in STEP1 then there should not be a problem when you are calling the service from your code.
try checking to check the authorisations/credentials implemented on the service, i have used the basic authentication protocol here, that might not be the same protocol that is being used by your service.
Insufficient privilege, just speculating here, it could be due to some security protocols that are implemented in the system.
Kind regards,
Vamsi