Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member187859
Participant

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.  :smile:

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. 

86 Comments
Former Member
0 Kudos

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

former_member187859
Participant
0 Kudos

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

AshwinDutt
Active Contributor
0 Kudos

Hello Paul,

Thanks for sharing . I tried it and worked as expected :smile:

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 ' :smile:

It would be great if you can share the information.

Regards,

Ashwin

Former Member
0 Kudos

Thanks Paul.

It is working as expected now.

Regards.

Dhruv

former_member187859
Participant
0 Kudos

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

AshwinDutt
Active Contributor
0 Kudos

Hello Paul,

Thank you so much for sharing the information. I will try CUD operation and get back to you.

Regards,

Ashwin

former_member188829
Active Contributor
0 Kudos

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.

Application Error
Error:System failure while executing your request.
Message:Could not read JSON: Invalid numeric value: Missing integer part (next char '-' (code 45)) at [Source: com.ibm.ws.webcontainer.srt.http.HttpInputStream@3f87eaf5; line: 1, column: 3]; nested exception is org.codehaus.jackson.JsonParseException: Invalid numeric value: Missing integer part (next char '-' (code 45)) at [Source: com.ibm.ws.webcontainer.srt.http.HttpInputStream@3f87eaf5; line: 1, column: 3]
  Please Contact Support team for more information.

Could you please suggest me, where i did the mistake?

Thanks,

Vishnu

former_member187859
Participant
0 Kudos

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. 

former_member188829
Active Contributor
0 Kudos

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

former_member187859
Participant
0 Kudos

Thanks for posting your successful code!

Greg-55
Explorer
0 Kudos

Hello Paul,

How do you call the GW service URI form ABAP?

Thanks,

Greg

former_member182465
Active Participant
0 Kudos

Thanks Paul and Vishnu for nice share.....

former_member187859
Participant
0 Kudos

Your question could be taken two ways, hopefully I clear it up with how I answer.  :smile:

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? 

Greg-55
Explorer
0 Kudos

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

former_member187859
Participant
0 Kudos

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

SyambabuAllu
Contributor
0 Kudos

Hi Paul,

Good Blog..we are waiting for this :smile:

Thanks,

Syam

Former Member
0 Kudos

Thanks for the Great blog Paul

Thanks

Sri

former_member189162
Participant
0 Kudos

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

former_member187859
Participant
0 Kudos

I get comment alerts :smile:

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

former_member189162
Participant
0 Kudos

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?

former_member187859
Participant
0 Kudos

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!

former_member189162
Participant
0 Kudos

Groovy, you rock man! Consider yourself "followed" ... maniacle laugh manicale laugh

Greg-55
Explorer
0 Kudos


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

Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos

Nice post !


Former Member
0 Kudos

Thanks Paul ,.Great Job,.,

0 Kudos

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>

Stephen3
Participant
0 Kudos

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

former_member187859
Participant
0 Kudos

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

Stephen3
Participant
0 Kudos

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

Former Member
0 Kudos

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

peter_simm2
Explorer
0 Kudos

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('01...')"
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

former_member187859
Participant
0 Kudos

Hi Peter,

Do you mind posting your code? I am a little confused by your wording. 

Thanks,

Paul

peter_simm2
Explorer
0 Kudos

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

Former Member
0 Kudos

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.

former_member187859
Participant
0 Kudos

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. 

Former Member
0 Kudos

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.

subbarao_ilam
Explorer
0 Kudos

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,

former_member187859
Participant
0 Kudos

This is probably related to your HTTP client configuration. Here's what I posted to another question from above:


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.


And I do - I hope this helps!

Paul

subbarao_ilam
Explorer
0 Kudos

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

EkanshCapgemini
Active Contributor
0 Kudos

Hi Subba,

Please check if you are behind some proxy.

Regards,
Ekansh

subbarao_ilam
Explorer
0 Kudos

Hi Ekansh,

what do you mean by behind proxy? can you please explain more?

Thanks,

Subba.

EkanshCapgemini
Active Contributor
0 Kudos

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

matt
Active Contributor

Very helpful. I just created a method which takes service and query as string parameters and returns a result string parameter:

So very simple.

  data service type string.
  service = me->url && i_service.

  data http_client type ref to if_http_client.
  cl_http_client=>create_by_url(
    exporting
      url                = service
    importing
      client             = http_client
    exceptions
      argument_not_found = 1
      plugin_not_active  = 2
      internal_error     = 3
      others             = 4 ).

  data: http_request type ref to if_http_request.
  http_request = http_client->request.
  http_request->set_method( 'POST' ).
  http_request->append_cdata( data = i_query ).

  http_client->send( ).
  http_client->receive( ).

  r_result = http_client->response->get_cdata( ).
Former Member
0 Kudos

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

 

   

former_member187859
Participant
0 Kudos

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

Former Member
0 Kudos

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.

Former Member
0 Kudos

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

former_member187859
Participant
0 Kudos

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

Former Member
0 Kudos

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

former_member187859
Participant
0 Kudos

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

Labels in this area