Consuming an External RESTful Web Service with ABAP in Gateway
Look, you don’t need to tell me. I already know the truth, deep in my bones: ABAP is not the language the cool kids use. Not even remotely on their radar. They’ve got their Scalas, and their Rusts, and all 30 billion javascript frameworks to build hot startups with. You can’t even play with ABAP unless you work for a place that runs SAP or you’re willing to download and install the massive (50 GB!) ABAP trial version.
But when you look under the covers at the system functionality that ABAP exposes in SAP systems, it becomes apparent that the frameworks, libraries, and system tools that you have at your command can be crafted into an engine to power a phenomenal array of projects. Just this morning I put together something that – while admittedly not incredibly useful all by itself – shows some of what you can accomplish if you have some familiarity with the tools SAP gives you in ABAP and Gateway.
Let me show you. It’s not a ridiculously complex build, and it’s just a slice of what you could do.
At a high level what I’ve done is find an external RESTful web service, write some ABAP to consume it from the SAP side, and expose that data back out through Gateway. It’s a little bit contrived, since you could easily call this service without Gateway mediating the connection…but I think there are occasional valid reasons to mediate the service through Gateway. You might have an account with the external service and need to manage your calls to it, or you might want to join the service data with other things from Business Suite services and make it all available in one entity type. Or you’re like me, and you just want to see if it could be done. 🙂
I created a developer account with world weather online, so that I could use its API for free. This lets you use a simple call to get a set of information on weather for a particular location, and in my case I use it to get the day’s forecast with a given zip code. If you sign up, you can use their neat API explorer to test out different ways to use the service.
If I call the main weather service with my home zip code, I get the following structure back (some unnecessary stuff has been trimmed):
<?xml version=“1.0” encoding=“UTF-8”?>
<data>
<request>
<type>Zipcode</type>
<query>55426</query>
</request>
<weather>
<date>2014-03-27</date>
<tempMaxC>5</tempMaxC>
<tempMaxF>40</tempMaxF>
<tempMinC>-6</tempMinC>
<tempMinF>22</tempMinF>
<windspeedMiles>15</windspeedMiles>
<windspeedKmph>24</windspeedKmph>
<winddirection>ESE</winddirection>
<winddir16Point>ESE</winddir16Point>
<winddirDegree>123</winddirDegree>
<weatherDesc>
<![CDATA[Light rain]]>
</weatherDesc>
<precipMM>9.6</precipMM>
</weather>
</data>
Knowing the structure of what comes back to me, I can build some simple ABAP to do the same thing. I set up a dictionary z-structure to hold the bits of data that I want to use:
I then set up a function module to do pull data from the service and put it into that structure:
FUNCTION zweather_read_zip.
*”—————————————————————
*”*”Local Interface:
*” IMPORTING
*” VALUE(IM_ZIPCODE) TYPE AD_PSTCD1
*” TABLES
*” ET_WEATHER STRUCTURE ZWEATHER
*”—————————————————————
DATA: lo_http_client TYPE REF TO if_http_client,
lv_service TYPE string,
lv_result TYPE string,
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,
ls_weather TYPE zweather,
lv_node_name TYPE string,
lv_node_value TYPE string.
lv_service = ‘http://api.worldweatheronline.com/free/v1/weather.ashx‘.
lv_service = lv_service && ‘?q=’ && im_zipcode && ‘&format=xml’.
lv_service = lv_service && ‘&key=[use your own!]’.
cl_http_client=>create_by_url(
EXPORTING
url = lv_service
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4 ).
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ).
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
“Prepare XML structure
CLEAR lv_result .
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( ).
“Navigate XML to nodes we want to process
lo_weather_element = lo_document->find_from_name_ns( ‘weather’ ).
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.
CLEAR ls_weather.
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( ).
CASE lv_node_name.
WHEN ‘date’.
REPLACE ALL OCCURRENCES OF ‘-‘ IN lv_node_value WITH ”.
ls_weather–forecast_date = lv_node_value.
WHEN ‘tempMaxF’.
ls_weather–high_temp_f = lv_node_value.
WHEN ‘tempMinF’.
ls_weather–low_temp_f = lv_node_value.
WHEN ‘windspeedMiles’.
ls_weather–wind_speed = lv_node_value.
WHEN ‘winddir16Point’.
ls_weather–wind_direction = lv_node_value.
WHEN ‘weatherDesc’.
ls_weather–description = lv_node_value.
WHEN ‘precipMM’.
ls_weather–precipitation = lv_node_value.
ENDCASE.
ADD 1 TO lv_node_index.
ENDWHILE.
APPEND ls_weather TO et_weather.
ENDFUNCTION.
I sprinkled some comments in the code to help, but I use the cl_http_client class to do the call to the service (and it can be set up and done in just 3 method calls), and then use a few of the xml library classes to parse the result and put it into the structure. You can see here that though I’ve only made the zip code dynamic in the call, you could actually be pretty dynamic in choosing services to leverage.
Why did I use a function module? It’s actually pretty easy to use a function module as a basis for building services in SEGW on your Gateway system, so it can be convenient to wrap custom functionality into a function module and then just import definitions. That’s what I did to set up the entity and entity set for this simple service:
Note especially that the GetEntity method is mapped with zip code as the incoming parameter:
After this, when I activated the service, it’s as simple as calling the URI with a parameter of some zip code that I want to see :
Like I mentioned before, by itself this isn’t much use. But combine this with some other information and you start to see what you can really pull together and expose through Gateway. It’s pretty awesome to think that anything you could pull from a REST service on the web can also be a resource for your application.
Hi Paul,
Thanks for the post. I am trying to create the function module but somehow I get an error in the following statements.
lv_service = lv_service && '?q=' && im_zipcode && '&format=xml'.
lv_service = lv_service && '&key=[use your own!]'.
ABAP is not able to recognize "&&" as an operator.
Also in the next statement what do you mean by "use your own".
Thanks for your time.
Regards,
Dhruv
Hi Dhruv,
'&&' is a shorthand for "CONCATENATE" that is available on the newest NetWeaver ABAP, so I think you might be on 7.31 or earlier. Sorry about that. The corresponding CONCATENATE statement would be something like:
CONCATENATE lv_service 'q=' im_zipcode '&format=xml&key=[use your own!]' INTO lv_service.
The [use your own!] represents the API key that you get from http://api.worldweatheronline.com/ when you register as a (free) developer on their site. I just didn't want to put my API key on the blog posting.
Hope that helps, please let me know if it doesn't!
Paul
Thanks Paul.
It is working as expected now.
Regards.
Dhruv
Hello Paul,
Thanks for sharing . I tried it and worked as expected 🙂
How do we pass our Payload to the method ' create_by_url ' when we have Create , Delete & Update operations ? & also Payload if we want to operate on BATCH mode for any of our CRUD operations ?
I know how to pass Payload to GW for any CRUD operations ( BATCH as well ).
Just want to know how actually we can pass to the method ' create_by_url ' 🙂
It would be great if you can share the information.
Regards,
Ashwin
Hi Ashwin,
I haven't yet done anything to push CUD of CRUD to an external REST service from SAP. But looking through the API structure of CL_HTTP_CLIENT and CL_HTTP_REQUEST, I believe you could do it.
Using the code above as a starting point, right after the call to create_by_url you have an object lo_http_client of type cl_http_client. This object has a publicly accessible attribute called "request", which is an object of type cl_http_request. The "request" object has support for changing the HTTP method (by calling method "set_method") and appending character data to the body (by calling method "append_cdata" or "append_cdata2").
It would look something like this. Inserted after the call the "create_by_url".
DATA: lo_http_request TYPE REF TO cl_http_request.
lo_http_request = lo_http_client->request.
lo_http_request->set_method( 'POST' ).
lo_http_request->append_cdata( data = [your request body] ).
Then I believe you could continue on with the execution of the http_client calls, as the client now has the request object set up correctly for other REST activities.
Thanks,
Paul
Hello Paul,
Thank you so much for sharing the information. I will try CUD operation and get back to you.
Regards,
Ashwin
Hi Paul,
I have tried as per your suggestion and below is the piece of code.
"Payload content
lv_post =
'{ "preOptionCodes": [ {"code": "7012", "priorityCode": true} ],"currentOptionCode": {"code": "0202", "priorityCode": true},"baseCode": "01J4H" }'.
"set http method POST
CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_post ).
"set protocol version
CALL METHOD lo_http_client->request->set_version(
if_http_request=>co_protocol_version_1_1 ).
"content type
CALL METHOD lo_http_client->request->if_http_entity~set_content_type
EXPORTING
content_type = 'application/json'.
"Set Header field
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = '*/*'.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept-Encoding'
value = 'gzip,deflate,sdch'.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept-Language'
value = 'en-US,en;q=0.8'.
CALL METHOD lo_http_client->request->append_cdata2( data = lv_post ).
" Formfield encoding
CALL METHOD lo_http_client->request->if_http_entity~set_formfield_encoding
EXPORTING
formfield_encoding = cl_http_request=>if_http_entity~co_encoding_raw.
I am getting below error.
Could you please suggest me, where i did the mistake?
Thanks,
Vishnu
On first glance of the message you're getting, it seems like the problem is on the WebSphere side, deserializing the JSON. I don't know a whole lot about that side of the equation...is there something you need to do to tell it that the values you're sending should be considered strings and not numbers?
I'm assuming because you have codes like "0202" and "01J4H" that you're not trying to send any numeric values across.
Hi Paul,
Thanks for your reply. I have used method SET_CDATA rather than APPEND_CDATA and it is working fine.
****JSON String to POST
lv_post =
'{"preOptionCodes":[{"code":"7012","priorityCode":true}],"currentOptionCode":{"code":"0202","priorityCode":true},"baseCode":"01J4H"}'.
****content type
CALL METHOD lo_http_client->request->if_http_entity~set_content_type
EXPORTING
content_type = 'application/json; charset=utf-8'."'application/json'.
****Set Header field
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = '*/*'.
*
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept-Encoding'
value = 'gzip,deflate,sdch'.
*
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept-Language'
value = 'en-US,en;q=0.8'.
*****Set the Data
DATA:lt_data TYPE xstring,
lv_len TYPE i.
lv_len = strlen( lv_post ).
CALL METHOD lo_http_client->request->set_cdata " Removed APPEND_CDATA
EXPORTING
data = lv_post
offset = 0
length = lv_len.
****Make the call
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ).
****Receive the Response Object
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
***Get the response content in Character format
CLEAR lv_result .
lv_result = lo_http_client->response->get_data( ).
WRITE:lv_result.
Thanks,
Vishnu
Thanks for posting your successful code!
Hi Vishnu,
I am doing the same thing posting json data using POST method to web API.
I have followed similar approach but still it does not post the data.
Can you kindly help here as I am unable to proceed.
Thanks.
hi can you please help me how we can pass INPUT as XML data to REST service , my requirement is similar to above. url: http://demo.mercurytravels.in/nextrapiv2.jsp
<flightsearchrequest>
<credentials>
<username>apiXXXXXXXX</username>
<password>apiXXXXXXX</password>
<officeid>XXXXXXXX</officeid>
</credentials>
<origin>BLR</origin>
<destination>BOM</destination>
<onwarddate>2014-10-10</onwarddate>
<returndate>2014-10-10</returndate>
<numadults>1</numadults>
<numchildren>1</numchildren>
<numinfants>1</numinfants>
<journeytype>OneWay</journeytype>
<requestformat>JSON</requestformat>
<preddeptimewindow />
<prefarrtimewindow />
<resultformat>XML</resultformat>
<prefclass>E</prefclass>
<prefcarrier>All</prefcarrier>
<excludecarriers />
<searchtype>Normal</searchtype>
<promocode />
<numresults>25</numresults>
<sortkey>default</sortkey>
<actionname>FLIGHTSEARCH</actionname>
</flightsearchrequest>
Hello Paul,
How do you call the GW service URI form ABAP?
Thanks,
Greg
Your question could be taken two ways, hopefully I clear it up with how I answer. 🙂
If you're asking about testing the GW service URI, then you can use the transaction /IWFND/GW_CLIENT. You won't have to use any ABAP to do that.
But I think you're asking about a scenario where you'd call an external GW system's URI from your ABAP program? In that case, you'd likely just have to change the full URI to include the external path to the GW system you're wanting to call.
Maybe you can explain more on what you're asking about?
Thanks Paul and Vishnu for nice share.....
Paul,
Maybe i'm reading this incorrectly, i thought this example was wrapping the function module with the GW GetEntity method and being utilized from ether an inside/out or outside/in perspective.
I was thinking that in the former one could either call the function module directly or call the GW service directly from maybe a ABAP program.
I'm questioning whether it's possible to call the GW service from within SAP and if this technique could be used in a similiar fashion as to call a wrapped RFC on a external system.
Sorry for the confusion, there's not much out there about SAP consuming external resouces.
Thanks,
Greg
Ah, ok. Thanks for the clarification. You're right, this example was wrapping the FM with the GetEntity method.
I think (not having tried it personally yet) that trying to consume the GW service from within the same system in ABAP code would be a daunting task, because there's a lot of stuff that happens at runtime and it would take a lot of work to just uncover what you need to have setup to make the call correctly. I think you'd be better off calling the FM directly.
Paul
Hi Paul,
How does this compare with using CL_REST_HTTP_CLIENT? Do you know of any examples? I see you're using a key provided by your registration to use the service, but any idea how this works with other various security mechanisms?
Thanks,
Greg
Hi Paul,
Good Blog..we are waiting for this 🙂
Thanks,
Syam
Thanks for the Great blog Paul
Thanks
Sri
Hi Paul,
Thanks for this blog. I am not sure if you still check the comments here or not, but I have a question for you about configurations to get this working.
Thanks!
-Kevin
I get comment alerts 🙂
If you want to ask the question publicly, feel free and I'll answer. Otherwise I think we need to "follow" each other to be able to exchange private messages.
Paul
wow thanks for the quick response!
Ok, kind of a newb question: Do we have to use Gateway to consume a REST Web Service like the weather service in an ABAP Function?
As long as you have some way to call out to that external service (like I did through the cl_http_client class), then any ABAP system could consume a REST web service.
Hit me up with a private message if you want to go through an example or something. I always find that stuff fun!
Groovy, you rock man! Consider yourself "followed" ... maniacle laugh manicale laugh
Nice post !
Thanks Paul ,.Great Job,.,
Hi Paul;
Thank you for putting together this example. I tried to recreate the function module in my test system. I discovered that the link below no longer works. The v1 has been changed to v2 and the output is slightly different. Can you update your code to get the some of the fields from the new lower "hourly" link.
Thanks
Stephen
http://api.worldweatheronline.com/free/v1/weather.ashx
Hi Stephen,
The link still works for me - provided that I give it the API key and some query information. Do you get some kind of error message when you try it in your code? Trying it from the browser would require a URL of the form:
http://api.worldweatheronline.com/free/v1/weather.ashx?key=[useyourownkeynotmine]&q=55426
Paul
Hi Paul
The link above worked for me as well. It doesn't work when I use my key but if I change the v1 to v2 with my key it does work. If you change the v1 to v2 in the link above, it fails with your key.
I guess the version of the API is tied to the key.
Stephen
Hi,
I have Restful API URL. I have to call it in background to trigger SMS. I use the same code which u mention in you blog create_url and then send method. But its not sending SMS to my mobile. Do we need gateway settings into this case. Normally when running the same URL using call_browser its working fine but its in foreground. I want this to be done in background without any pop-up. Do we need and HTTP settings, If yes then give me detail steps.
Thanks in advance. For this useful post also.
Cheers,
Nainesh Patadia
Hi Paul,
I followed your guide. Unfortunately I did anything
wrong. When executing transaction /IWFND/SUTIL_GW_CLIENT to test the service, I
get the following error message:
Network Error (tcp_error)
A communication error occurred: "Connection refused"
The Web Server for your query "http://sfc1sappmcid1.[xxxxx].com:8010/sap/opu/odata/sap/ZWEATHER_DEMO_SRV/DailyWeatherCollection('01109')"
may be down, too busy, or experiencing other problems preventing it from responding to requests. You may wish to try again at a later time.
It seems the system passes the SAP service to the internet not the URL. When calling the link
http://api.worldweatheronline.com/free/v2/weather.ashx?q=&format=xml
&key=[mykey]
I get the expected weather data. Do you have any idea what I did wrong?
Thank you, Peter
Hi Peter,
Do you mind posting your code? I am a little confused by your wording.
Thanks,
Paul
Hi Paul,
Thanks for your quick reply.
I am giving my code here.
" Local Vars
DATA: lo_client TYPE REF TO if_http_client,
lc_url TYPE string,
lc_content TYPE string,
lt_html TYPE TABLE OF string.
" Set html page to load
lc_url = 'http://www.sap.com'.
" Create the HTTP client
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = lc_url
IMPORTING
client = lo_client
EXCEPTIONS
OTHERS = 1.
IF sy-subrc IS NOT INITIAL.
" Error
EXIT.
ENDIF.
" Set the Request type to GET
lo_client->request->set_header_field( name = '~request_method'
value = 'GET' ).
" Make the call
lo_client->send( ).
" Receive the Response Object
CALL METHOD lo_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4.
IF sy-subrc IS NOT INITIAL.
" Error
EXIT.
ENDIF.
I am using above code and getting connection refuse error.
My requirement is to trigger Restful API which sends SMS to mobile.
I have change URL from Restful SMS API to www.sap.com here in this post rest all is same.
You should try program RSHTTP20 and put in the URI you're trying to use there (I suggest using 'http://www.sap.com/index.html' instead of sap.com, since sap.com redirects to the index page).
What that program will do is go through the HTTP request process and tell you what kind of response you're getting, or it will tell you if there's an error in your SAP_HTTP RFC setup. I suspect that that's where the error is - I have a test system that isn't configured to make outbound HTTP calls and I get the same error you're getting, but when I use a system properly configured to make outbound HTTP calls I can get a success from the RECEIVE method.
Hope this helps.
Thanks Paul,
Can you let me know steps to check that SAP_HTTP Rfc is configured or not in my system?
So, I can check and test it again.
Thanks a ton for your quick reply.
Hi Paul,
thank you for your fast answer. I went through my setup and made some screenshots and copies from what I did for configuration. Probably I did a stupid mistake but I am not able to identify it.
Thank you,
Peter
1. Functionmodule ZWEATHER_READ_ZIP
First I have created the FM ZWEATHER_READ_ZIP with the following coding:
FUNCTION zweather_read_zip.
*"--------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(IM_ZIPCODE) TYPE AD_PSTCD1
*" TABLES
*" ET_WEATHER STRUCTURE ZWEATHER
*"-------------------------------------------------------------
DATA: lo_http_client TYPE REF TO if_http_client,
lv_service TYPE string,
lv_result TYPE string,
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,
ls_weather TYPE zweather,
lv_node_name TYPE string,
lv_node_value TYPE string.
lv_service = 'http://api.worldweatheronline.com/free/v2/weather.ashx'.
lv_service = lv_service && 'q=' && im_zipcode && '&format=xml'.
lv_service = lv_service && '&key=xxxxxxxxxxxxxxxxxxxxxxxxxxx'.
cl_http_client=>create_by_url(
EXPORTING
url = lv_service
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4 ).
lo_http_client->send(
EXPORTING
timeout = 20
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4 ).
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
"Prepare XML structure
CLEAR lv_result .
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( ).
"Navigate XML to nodes we want to process
lo_weather_element = lo_document->find_from_name_ns( 'weather' ).
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.
CLEAR ls_weather.
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( ).
CASE lv_node_name.
WHEN 'date'.
REPLACE ALL OCCURRENCES OF '-' IN lv_node_value WITH ''.
ls_weather-forecast_date = lv_node_value.
WHEN 'tempMaxF'.
ls_weather-high_temp_f = lv_node_value.
WHEN 'tempMinF'.
ls_weather-low_temp_f = lv_node_value.
WHEN 'windspeedMiles'.
ls_weather-wind_speed = lv_node_value.
WHEN 'winddir16Point'.
ls_weather-wind_direction = lv_node_value.
WHEN 'weatherDesc'.
ls_weather-description = lv_node_value.
WHEN 'precipMM'.
ls_weather-precipitation = lv_node_value.
ENDCASE.
ADD 1 TO lv_node_index.
ENDWHILE.
APPEND ls_weather TO et_weather.
ENDFUNCTION.
2. Create project in SEGW
3. I went to SPRO > SAP NetWeaver > Gateway > OData > General Setting > Activate and Maintain Services (/IWFND/MAINT_SERVICE)
Here I have activated the Service as shown in the screenshot:
When done I have tested the service pressing the “Gateway Clienet” button in transaction /IWFND/MAINT_SERVICE. Here I passed the parameter DailyWeatherCollection('01109') into the URI and pressed “execute”.
As you can see in the screenshot above, it seems the system passes the service's address to the internet, not the URL to the weather API.
Thank you,
Peter
Hi Paul,
I have tried to implement this example with same API by registering in worldweatheronline.
Some how when I try to execute the service call I am getting return code "1 = http_communication_failure" from the method call
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
Could you pleas let me know how to resolve this, are there any other setting/config we have to maintain before calling the API?
Thanks in advance.
Thanks,
Subba,
This is probably related to your HTTP client configuration. Here's what I posted to another question from above:
And I do - I hope this helps!
Paul
Hello Paul,
Thanks a lot for quick reply, I ran the program RSHTTP20 with my URL given below
http://api.worldweatheronline.com/free/v2/weather.ashx?q=91722&format=xml&key=<myapikey>
I got the response but still I am getting the same connection error for RECEIVE method. Can you please adivse?
Thanks,
Subba
Hi Subba,
Please check if you are behind some proxy.
Regards,
Ekansh
Hi Ekansh,
what do you mean by behind proxy? can you please explain more?
Thanks,
Subba.
Hi Subba,
If you are using the corporate network, you might be using some proxy to connect to internet. If the proxy is in place, you need to set it up in the SAP also in order to communicate to internet. This was the case with me. So I chose to create a RFC destination with proxy and its credentials, then used cl_http_client=>create_by_destination instead of 'create_by_url' and then use cl_http_utility=>set_request_uri( request = lo_http_client->request uri = lv_service ) to set up the query URI.
Regards,
Ekansh
Very helpful. I just created a method which takes service and query as string parameters and returns a result string parameter:
So very simple.
Hi Paul,
Thanks for this post. Such a piece of gem.
Well the weather API works fine as per your code, but when i try to invoke API for google analytic ( which gives output in JSON format), lo_http_client->receive is throwing an exception "http_communication_failure", any idea what could be the issue.
Thanks
Hi Yogendra,
You should post your code. I'll bet google analytics requires some hand-holding on authenticating requests to their API. Curious to see how you're handling that (be sure to scrub any actual authentication data from your code).
Paul
Hi paul,
I wanted to understand if its mandatory to develop a gateway service , while consuming an external Odata service. If we have an ABAP program , to consume the external service as described by you, We can execute the program as is.
Please share your views.
Thanks
Meghna
Hi Meghna,
I'm having a little trouble understanding your question. Are you asking if you should use an ABAP program that already consumes an external service as the driving logic for a Gateway OData service? If so, then yes I think you'd want to save the time and effort - and you can easily re-use existing ABAP code when you create Gateway services.
But I'm not sure that I'm answering your question. Please let me know if I'm misunderstanding.
Thanks!
Paul
Hi Paul,
Thank you for the quick reply.Sorry for the confusion.
My doubt is , do we need to develop an SAP gateway service to consume an external rest service?Can we consume an external service by a stand alone ABAP program only,without any development of SAP gateway service.
Do we need to develop an SAP gateway service at all to achieve this?I wanted to confirm if a stand alone ABAP program should be able to consume an external REST service,without any additional gateway development.Correct me if i am wrong.
Meghna
Hi Meghna,
OK - I understand your question. Thanks for clarifying.
You do NOT need to develop an SAP Gateway service to consume an external REST service. Simply use the cl_http_client (or cl_rest_http_client, by example elsewhere) to make calls to that external service and then do whatever you want with that data. Anywhere you can write ABAP (function modules, report programs, classes, etc) can consume external REST services.
Hope that helps!
Paul
Thank you ! that clarifies it.
and thanks for sharing all the details in this blog.
It really helps!
Meghna
HI paul,
If we have to pass some values in the header , like the api key and format.
How can we achieve it.
I have tried the following :
CALL METHOD lo_http_client->request->set_method( if_http_request=>CO_REQUEST_METHOD_GET ).
"Set Header field
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'API-KEY'
value = 'XXXXXXXXX'.
"Set Header field
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = 'application/xml'.
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ).
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
But the code hangs indefinitely on the 'Receive' method.
Meghna
Hi Paul,
just came across your blog - have some query in this regards,
would appreciate your reply.
Thanks,
Ashish.
Hi Paul,
Thanks for the post. I have a question, can I do similar code for a "https" service call.
Thanks,
JM
HI paul,
Can we use this for HTTPS service calls?
If we have to pass some values in the header , like the api key and format.
How can we achieve it.
I have tried the following :
CALL METHOD lo_http_client->request->set_method(if_http_request=>CO_REQUEST_METHOD_GET ).
"Set Header field
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'API-KEY'
value = 'XXXXXXXXX'.
"Set Header field
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = 'application/xml'.
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ).
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
But the code hangs indefinitely on the 'Receive' method.
Meghna
Hi Meghna,
I would try this on a simple known good https url - like https://www.google.com. Take out the header field params and just do the call that way. See if you get a real response...the problem could possibly be in your system's overall HTTP setup.
If you get the right stuff from the bare HTTPS request, then what I do is use a tool like Postman or Advanced Rest Client (both Chrome extensions, but you can find good stuff for Firefox or other browsers) and make sure my header parameters are appropriate for the web API I'm calling.
If you're willing to share more code I can probably help more.
Paul
Hi Paul,
Thanks for this post.
I have one scenario to be mapped in SAP. Can you please help me out?
I need to call a JSON API (https://api-sandbox.grovo.com/users) from ABAP. This API needs a valid token which to be received from another API call (https://api-sandbox.grovo.com/token), after providing API id and password.
for API details - https://grovo-api.readme.io/v1.0/docs
For each API subsequent call I would need to call this Token API.
Can you please help me understand which SAP function module / class to call to get token from (https://api-sandbox.grovo.com/token) API , and how to pass this token value to call subsequent API (https://api-sandbox.grovo.com/users))?
Thanks
Vijay
Hi Paul,
thank you for this Post. It helped me a lot.
However i do have some questions.
I am trying to call an OData Service with Authentication involved.
I know we can use the authenticate method in the CL_HTTP_CLIENT class, but is there a way to use the Create_by destination method so the user/ID password details can be stored securely in an SM59 connection.
While doing the SM59 Configuration, how can we pass the parameters to the URI?
Have you considered/encountered such a scenario?
Kind Regards,
Vamsi
Hi Vasmi,
I see that you put a blog up recently on this topic - I'm sorry I was too late to respond to try to help you, but I'm glad that you put something out there that I could learn from. Well done!
Regards,
Paul
Hello Paul,
I find the article interesting, hope you can send private message, need your help. thanks in advance.
This is a site for sharing information. Do not ask for private messages.
Sorry, I just dont have a way to ask pauls help and might be off topic if I post my concern here.I can create a new thread just want pauls attention thats all. Tnks
This is one way of attracting his attention. Paging Paul J. Modderman 🙂
I engaged with Jeff privately on this. If the discussion is at all worthwhile to be made generic and shared I will absolutely do so.
Hi Paul,
Thanks for the blog. I have created a FM and using the code in my FM.
But I'm getting a dump at this line.
lo_weather_element = lo_document->find_from_name_ns( 'weather' ).
lo_weather_nodes = lo_weather_element->get_children( ).
The issue is the lo_weather_element is Initial and not having the corresponding node. I have checked doing F5 at this statement. But it goes to the below code and comes out of it.
method if_ixml_document~find_from_name_ns
by kernel module abkm_iXMLDocument_FindFromNameNS.
endmethod.
Can you please share some info on this about how to make this work.
Thank you,
Kritika
Hello,
The requirement is to consume a web service REST-POST. Base URL is provided along with other credentials which are constant value. Web service will return a JSON format which I need to map into ABAP structure. Following the above code and comments from Paul and other members, I tried to start with CREATE BY URL. It seems didn't work and came to know that I need to trigger a POST method using FORM DATA. I have no clue how to achieve this using FORM DATA in order to prepare my URL.
Once the URL is triggered and JSON is returned. It will be mapped into ABAP structure, so planning to use the /UI2/CL_JSON=> deserialize to convert the JSON data into ABAP structure. Kindly let me know how to prepare the URL using POST method for JSON.
Hi,
I have implemented both GET/POST everything works as expected ..is that possible to implement as below PUT method.
lo_client->request->set_method( 'PUT' ).
Let me know if you have any advice's on this.
Thanks,
Syam
Hi Paul,
Thanks for the blog. I have created a FM using the above given code.
But I’m getting a dump at this line.
lo_weather_element = lo_document->find_from_name_ns( ‘weather’ ).
lo_weather_nodes = lo_weather_element->get_children( ).
I tried to execute the same in the debugger and found that the API key is invalid.
I have generated the API key by registering as a (free) developer on https://developer.worldweatheronline.com/auth/register site.
Could you please help by providing the appropriate solution.
Thanks.
Rohini
Hi Rohini,
It’s been a few years since I looked at this stuff. The world weather online service may have changed how it checks/supplies keys. You may need to switch “free” for “premium” in the URL for the api call.
You might also make sure you're using the right version of the API call in the URL. Since you signed up recently, you'll need "v2" in the URL instead of "v1".
If that doesn’t work, try using a tool like Postman to figure out how the API call needs to look before plugging that back into the ABAP code.
Let me know if that helps!
-Paul
HI Paul,
{"Time":"2017-03-13T05:05:39-04:00","Result":"9"}
This my webservice result in json format. Can anybody help me how to read this using ABAP? i tried with above piece of code but i am getting dump.
Hi Vamsi,
The above code expects the results of a web service call in XML format. If the service you're calling is returning JSON, then may I suggest looking at the below for a call transformation solution to serializing/deserializing JSON<==>ABAP.
E.g. https://blogs.sap.com/2013/07/04/abap-news-for-release-740-abap-and-json/
Also https://blogs.sap.com/2013/01/07/abap-and-json/
Hope this helps!
-Paul
@Paul J. Modderman: Thanks for the great blog post.
I want to ask here you have provided URL manually in the program code. This approach is not practical for typical business application. How to achieve the same via reading configuration done on gateway.
Another point what if at design time the structure of requested resource from web service is not known, so what would be approach to consume it. Do we have enriched client side library in SAP so less parsing is required in such case?
Thanks for your help.
Hi Amit,
You can achieve URL configuration in any number of ways. A custom table, a TVARV value...anything like that. Store the URL as a string in one of those places, and read it at runtime.
If you don't know at design time what the structure will look like, you can look at an approach like the one in this git repository: https://gist.github.com/mydoghasworms/2291540 . Method "json_to_data" should let you have any json be output as generic ABAP data. Though if you don't know the structure of what you're asking for from the web service, it may be hard to extract the right thing from that structure for your use.
Paul
Hi Paul,
Thanks alot for the wonderful post.
I tried your example but i am getting initial value when executing this statement ( lo_weather_element = lo_document->find_from_name_ns( ‘Weather’ ).
I looked at the blog and tried /o/IWFND/GW_CLIENT the transaction and executed it by giving the URL then i received an error “HTTP Receive failed: SSL handshake with api.worldweatheronline.com:443 failed: SSSLERR_PEER_CERT_UNT” .
Can you please let me know how i can resolve this error.
But when I execute same URL from Program RSHTTP20 i am getting connect Error: Open SSL not available.
Thanks,
Kiran
Hi Paul,
Firstly good blog. Guess this was needed when T-code "/IWBEP/OCI_SRV_GEN" wasn't available. However would like to know if you try to register external OData service( example XS Engine Odata) onto Gateway and consume on SAPUI5 app on gateway? As when I did only HHTP GET methods works and no POST and other HTTP methods
Reference: http://www.saplearners.com/how-to-consume-external-odata-services-in-sap-netweaver-gateway/
Hi Paul,
This is something new to us. We have a requirement to access to a portal using REST API with login id and password and read the data from that portal. We are not understanding from where to start with. Do we first need to create a service in SEGW and link a method/FM of ABAP to it? Bit confused.
Is it possible to provide your email address from where we can contact you?
Thanks,
Madhura.
Hi Paul,
Thanks for posting such a valuable post.But my question is how to post complex xml like following
<?xml version="1.0" ?>
<AccessRequest xml:lang='en-US'>
<AccessLicenseNumber>XXXXXXXXXXXXXXXXXXX</AccessLicenseNumber>
<UserId>XXXXXXXX</UserId>
<Password>XXXXXXX</Password>
</AccessRequest>
<?xml version="1.0" ?>
<AddressValidationRequest xml:lang='en-US'>
<Request>
<RequestAction>XAV</RequestAction>
</Request>
<AddressKeyFormat>
<AddressLine>100 Broad Street</AddressLine>
<Region></Region>
<PoliticalDivision2>NEWARK</PoliticalDivision2>
<PoliticalDivision1>NJ</PoliticalDivision1>
<PostcodePrimaryLow>75050</PostcodePrimaryLow>
<CountryCode>US</CountryCode>
</AddressKeyFormat>
</AddressValidationRequest>
Please give me some advice
Thankyou so much
HI Paul,
I need to pass an authorization header in a HTTP Post service.
When i use the create_by_destination method, it always triggers a logon popup even when "NO Logon" is chosen in the RFC destination definition.
I have used the propertytype_no_logon_popup but it does not suppress the logon popup.
but whenever i call with create_by_destination the logon popup is always triggered.
we cannot use the create_by_url option because, we do not want to hardcode the URL.
Is there any way to configure the RFC destination so that, it does not trigger the popup and just uses the Authorization header?
Kind Regards,
Vamsi
HI,
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?
https://answers.sap.com/questions/615947/trigger-scp-from-abap-program.html
Hi Paul,
Hope you are doing good.
I was following your this blog and was tryinging to replicate. But I am facing some issues. Could you please guide me further.
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S32 {
color: #3399FF;
}
.L0S55 {
color: #800080;
}
.L0S70 {
color: #808080;
}
http://api.worldweatheronline.com/premium/v1/weather.ashx?q=London&format=xml&date=2018-08-21&key=mykey
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S31 {
font-style: italic;
color: #808080;
}
.L0S52 {
color: #0000FF;
}
.L0S55 {
color: #800080;
}
DATA: lo_http_client TYPE REF TO if_http_client,
lv_service TYPE string,
lv_result TYPE string,
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,
im_zipcode TYPE ad_pstcd1,
* ls_weather TYPE zweather,
lv_node_name TYPE string,
lv_node_value TYPE string.
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S33 {
color: #4DA619;
}
.L0S55 {
color: #800080;
}
lv_service = 'http://api.worldweatheronline.com/premium/v1/weather.ashx?q=London&format=xml&date=2018-08-21&key= mykey'
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S52 {
color: #0000FF;
}
.L0S55 {
color: #800080;
}
Data :lv_rc TYPE i.
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S32 {
color: #3399FF;
}
.L0S52 {
color: #0000FF;
}
.L0S55 {
color: #800080;
}
.L0S70 {
color: #808080;
}
cl_http_client=>create_by_url(
EXPORTING
url = lv_service
IMPORTING
client = lo_http_client
EXCEPTIONS
argument_not_found = 1
plugin_not_active = 2
internal_error = 3
OTHERS = 4 ).
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ).
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ).
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S31 {
font-style: italic;
color: #808080;
}
.L0S52 {
color: #0000FF;
}
.L0S55 {
color: #800080;
}
.L0S70 {
color: #808080;
}
"prepare xml structure
CLEAR lv_result .
lv_result = lo_http_client->response->get_cdata( ).
I am getting error code '401.
Message as follows 'Description: Authorization is required for access to this proxy'.
But when I execute, the URL in the program 'RSHTTP20' , I am getting return code as 200.
Could you please guide, what could be the issue behind and how to resolve it ?
Thank you.
Regards,
Atul M
If someone has done this with SAP Concur API's, I'd love it if they could share the code!
Hello to all , i use this code , and works really good , i can't thanks enough , but i have a problem when i get my data , is in string form , i use this
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S31 {
font-style: italic;
color: #808080;
}
.L0S32 {
color: #3399FF;
}
.L0S33 {
color: #4DA619;
}
.L0S55 {
color: #800080;
}
.L0S70 {
color: #808080;
}
lo_weather_element = lo_document->find_from_name_ns('search_api').
lo_weather_nodes = lo_weather_element->get_children( ).
lv_node_length = lo_weather_nodes->get_length( ). " CUANTAS FILAS HAY
lv_node_index = 0.
SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S55 {
color: #800080;
}
.L0S70 {
color: #808080;
}
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( ).
The item properly is RESULT but if i put result is getting separeted in columns as the example says , but , when i use this "search api" is getting me the right amount of rows or items , but all 1 place , is a string with no separetor .
Can someone please give a hand
i implemented your code and got api as well , but getting error , i attached snap of api and error , please let me know if i have missed anything
It looks like you hard-coded square brackets around your API key. That might be the issue? The API key in your URL shouldn't have brackets.
Hi Paul,
I hope you are safe and doing well!!
i am new to making HTTP calls from ABAP to external RESTful API Services. I have a requirements where I have been given a service /sap/opu/odata/IBP/PLANNING_DATA_API_SRV/. I have to use this to post data back. Please let me know how I should proceed. i have created a sample ABAP program as shown below:
*************************************************************************************
**********************************CODING FOR THE GET METHOD***********
*************************************************************************************
*Create the HTTP client
cl_http_client=>create_by_destination(
EXPORTING
destination = c_rfcdest " Logical destination (specified in function call)
IMPORTING
client = lo_http_client " HTTP Client Abstraction
EXCEPTIONS
argument_not_found = 1
destination_not_found = 2
destination_no_authority = 3
plugin_not_active = 4
internal_error = 5
OTHERS = 6
).
CREATE OBJECT lo_rest_client
EXPORTING
io_http_client = lo_http_client.
* Create request instance
lo_request = lo_rest_client->if_rest_client~create_request_entity( ).
* Set HTTP version
lo_http_client->request->set_version( if_http_request=>co_protocol_version_1_0 ).
IF lo_http_client IS BOUND AND lo_rest_client IS BOUND.
*Fill headers and set URI for GET Method
*Create URI for the client
lv_query = 'getTransactionID'.
cl_http_utility=>set_request_uri(
EXPORTING
request = lo_http_client->request
uri = lv_query ).
ENDIF.
*Update the HTTP method
lo_http_client->request->set_method( method = lo_http_client->request->co_request_method_get ).
*********************************
*set Content type
lo_http_client->request->if_http_entity~set_content_type(
content_type = 'application/json' ).
lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.
*
*set header field for festching x-csrf-token
lo_http_client->request->set_header_field(
name = 'x-csrf-token' " Name of the header field
value = 'Fetch' ). " HTTP header field value
*Trigger the GET Method
lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4
OTHERS = 5
).
lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4
).
IF sy-subrc <> 0.
MESSAGE e000(oo) WITH 'Processing failed !'.
ENDIF.
DATA(wf_string1) = lo_http_client->response->get_cdata( ).
*
*Get x-csrf token from earlier response
lv_token = lo_http_client->response->get_header_field('x-csrf-token'). " Name of the header field
lv_session = lo_http_client->response->get_header_field('set-cookie').
*Convert JSON response to XML
DATA: json TYPE xstring.
*Return the HTTP body of this entity as binary data
json = lo_http_client->response->get_data( ).
CALL TRANSFORMATION id SOURCE XML json
RESULT XML DATA(xml).
DATA(reader) = cl_sxml_string_reader=>create( json ).
DATA(writer) =
CAST if_sxml_writer( cl_sxml_string_writer=>create( ) ).
TRY.
DO.
CLEAR lwa_node.
DATA(node) = reader->read_next_node( ).
IF node IS INITIAL.
EXIT.
ENDIF.
writer->write_node( node ).
CASE node->type.
WHEN if_sxml_node=>co_nt_element_open.
DATA(open_element) = CAST if_sxml_open_element( node ).
DATA(attributes) = open_element->get_attributes( ).
LOOP AT attributes INTO DATA(attribute).
lwa_node-node_type = `attribute`.
lwa_node-prefix = attribute->prefix.
lwa_node-name = attribute->qname-name.
lwa_node-nsuri = attribute->qname-namespace.
IF attribute->value_type = if_sxml_value=>co_vt_text.
lwa_node-value = attribute->get_value( ).
ELSEIF attribute->value_type =
if_sxml_value=>co_vt_raw.
lwa_node-value_raw = attribute->get_value_raw( ).
ENDIF.
IF lwa_node-value = 'LOCDESCR' OR lwa_node-value = 'LOCID'.
APPEND lwa_node TO lt_node.
ENDIF.
ENDLOOP.
CONTINUE.
WHEN if_sxml_node=>co_nt_element_close.
DATA(close_element) = CAST if_sxml_close_element( node ).
CONTINUE.
WHEN if_sxml_node=>co_nt_value.
DATA(value_node) = CAST if_sxml_value_node( node ).
lwa_node-node_type = `value`.
IF value_node->value_type = if_sxml_value=>co_vt_text.
lwa_node-value = value_node->get_value( ).
ELSEIF value_node->value_type = if_sxml_value=>co_vt_raw.
lwa_node-value_raw = value_node->get_value_raw( ).
ENDIF.
APPEND lwa_node TO lt_node.
CONTINUE.
WHEN OTHERS.
lwa_node-node_type = `Error`.
APPEND lwa_node TO lt_node.
EXIT.
ENDCASE.
ENDDO.
CATCH cx_sxml_parse_error INTO DATA(parse_error).
ENDTRY.
* GET TRANSACTION ID
DESCRIBE TABLE lt_node LINES DATA(lv_lines).
READ TABLE lt_node INTO DATA(lv_val) INDEX lv_lines.
IF sy-subrc = 0.
DATA(tranid) = lv_val-value. "transaction ID
ENDIF.
************************END OF LOGIC TO GET TRANSACTION ID**************************
*****************************************************************************************************
******************* LOGIC TO SEND DATA USING POST MTHOD *****
*****************************************************************************************************
free lo_http_client.
CONCATENATE 'https://.......scmibp.ondemand.com/sap/opu/odata/IBP/PLANNING_DATA_API_SRV/'
'(' '''' tranid '''' ')' INTO lv_url.
cl_http_utility=>set_request_uri(
EXPORTING
request = lo_http_client->request " HTTP Framework (iHTTP) HTTP Request
uri = lv_url " URI String (in the Form of /path?query-string)
).
ENDIF.
************************LOGIC TO CREATE NESTED JSON PAYLOAD*******************************
*** ABAP to JSON
*Create the nested JSON file to be used for data update
IF tranid <> space.
DATA(nav_unipa_2021) = VALUE t_nav_unipa_2021( ( keyfigure = 'CONSENSUSDEMANDQTY'
keyfiguredate = '2021/02/25'
product = 'E6603GA0'
customer = '54000'
location = '5450' ) ).
DATA(resp) = VALUE ty_response( transactionid = tranid
aggregationlevelfieldstrings = 'KEYFIGURE, KEYFIGUREDATE, PRODUCT, CUSTOMER, LOCATION'
navhasbroio = nav_unipa_2021 ).
DATA(json_response) = /ui2/cl_json=>serialize(
data = resp
).
**********************END OF LOGIC TO CREATE NESTED JSON PAYLOAD*********************
*Update the HTTP method
CALL METHOD lo_http_client->request->set_method
EXPORTING
method = lo_http_client->request->co_request_method_post.
*set the token received from GET method
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'x-csrf-token'
value = lv_token.
*set the cookie received from the GET Method
CALL METHOD lo_http_client->request->set_cookie
EXPORTING
name = 'set-cookie'
value = lv_session.
*content type
CALL METHOD lo_http_client->request->set_content_type
EXPORTING
content_type = 'application/json'.
**Set body for the HTTP post request
lo_http_client->request->set_cdata( data = json_response ).
*Trigger the POST Method
lo_http_client->send( "Send the HTTP request
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
http_invalid_timeout = 4
OTHERS = 5
).
lo_http_client->receive( "receive the response
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
OTHERS = 4
).
DATA(l_result) = lo_http_client1->response->get_cdata( ).
write:/ l_result.
ENDIF.
Need your help. Please assist. i am stuck and dont know how to proceed now.
Thanks,
Ashok
thanks for sharing this, very helpful!