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: 
vamsixk
Active Participant

This can be considered a continuation of the earlier Blog Post i have written Consume Odata Service in ABAP CL_HTTP_CLIENT->CREATE_BY_DESTINATION. In the earlier post it is described how to trigger a GET method of the Odata Service.

This post would not have been possible if not for the wonderful Community that is SCN. Thank You wouter.venhuizen , thomas.schmidt8 and ashwindutt.rfor your cotributions. i would Award you more than 10 Points if i could. For pointing me in the right Direction. Without this i would still be stumbling, lost in the Wildlands of SCN.

Calling https web service POST method from ABAP | SCN.

Even though each question and answer I find may not be particular to the issue i am facing, it always help me channel my investigation in the right direction.

I hope this blog Post does the same.

The Requirement:

We had a recent requirement in our team where we were required to modify some Data in the HANA system from ECC.

There was already a HANA service that we being used by the UI to create the same data, So the solution direction was to use the same service to post Data from ECC to HANA.

The Solution:

The approach was to call a HTTP Post method from ECC using the CL_HTTP_CLIENT class.

the process is the same for instantiating a HTTP Client has already been described in my earlier blog.

The Difference between a GET method and the Post Method for Odata is the X-CSRF token handling.

Since the HTTP POST method is a modifying call, an X-CSRF Token has to be passed for security purposes.

More information on this Topic in the below Link

Cross-Site Request Forgery Protection - SAP Gateway Foundation (SAP_GWFND) - SAP Library

In one of the posts i saw related to this topic on SCN(usage of CSRF token in ABAP report for POST request), the Classes being used were unavailable in ECC because in our landscape the ECC and GATEWAY implementations are on two separate systems.

in the Above post once the X-CSRF Token is fetched the REST object and the HTTP Client are refreshed.

They are re instantiated and then the Token is used in a HTTP POST request. this for some reason was not working when i was using the Class Methods available for CL_HTTP_CLIENT.

the Work around implemented, was to use the same object instantiation for both the GET and POST methods.

  1. Instantiate the Client
  2. Fill headers and set the URI for the GET request of the same Entity for which we want to POST.
    1. While filling the headers we have to pass a header Field with name 'X-CSRF-Token' and value 'Fetch'.
  3. Trigger the  HTTP GET request,
    1. The X-CSRF token can be retrieved from the Response attribute of the HTTP Client object.
  4. Fill the headers of the request Attribute once again. but this time we set the X-CSRF token with the value retrieved from step 3, instead of "Fetch".
    1. Set the Request HTTP method to POST
    2. Fill the BODY of the HTTP request with the data that has to be modified
    3. Trigger the HTTP post request

Note: In between step 3 and 4 we should not refresh the HTTP Client Object that was used to fetch the X-CSRF token.

          



Detailed Code for above Steps:-

Preparatory Step:- Create RFC destination in SM59


(please refer to Step 1 in my earlier post) Consume Odata Service in ABAP CL_HTTP_CLIENT->CREATE_BY_DESTINATION.

Step1:- Instantiate the HTTP Client in ABAP


DATA:  l_query TYPE string,

       l_body TYPE string,

       l_token TYPE string,       

       l_result TYPE string.

DATA: lo_http_client TYPE REF TO if_http_client.

CONSTANTS:  c_rfchana   TYPE rfcdest VALUE 'RFCHANA', " RFC Destination

            c_query     TYPE string VALUE '/ModifyMaterial'. " Entity name

.

* fetch X-CSRF token

DATA: l_query TYPE string.    " URI Query


DATA: lo_http_client TYPE REF TO if_http_client.

* Create the HTTP CLient

  CALL METHOD cl_http_client=>create_by_destination

    EXPORTING

      destination              = C_RFCHANA

    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 NOT sy-subrc IS INITIAL.

  ENDIF.

STEP 2:- Fill headers and set URI for GET Method

* create the URI for the client.

  l_query = im_query.

  CALL METHOD cl_http_utility=>set_request_uri

    EXPORTING

      request = lo_http_client->request

      uri     = l_query.

* update the HTTP Method

  CALL METHOD lo_http_client->request->set_method

    EXPORTING

      method = lo_http_client->request->co_request_method_get.

* set Content type

  CALL METHOD lo_http_client->request->if_http_entity~set_content_type

    EXPORTING

      content_type =  'application/json'.

* set header field for fetching X-CSRF token

  CALL METHOD lo_http_client->request->set_header_field

    EXPORTING

      name  = 'X-CSRF-Token'

      value = 'Fetch'.

Step 3:- Trigger the GET Method

  lo_http_client->send(

      EXCEPTIONS

        http_communication_failure = 1

        http_invalid_state         = 2 ). "Send the HTTP request

  lo_http_client->receive(

    EXCEPTIONS

      http_communication_failure = 1

      http_invalid_state         = 2

      http_processing_failed     = 3 ). "receive the response

****GET x-csrf TOKEN from earlier response

CALL METHOD lo_http_client->response->get_header_field

  EXPORTING

    name  = 'X-CSRF-Token'

  RECEIVING

    value = l_token.

Step 4:- Fill headers and Body for HTTP POST method

* Set X-CSRF- Token in the new request.

CALL METHOD lo_http_client->request->set_header_field

  EXPORTING

    name  = 'X-CSRF-Token'

    value = l_token.

* update the HTTP Method

CALL METHOD lo_http_client->request->set_method

  EXPORTING

    method = lo_http_client->request->co_request_method_post.

****content type

CALL METHOD lo_http_client->request->set_content_type

  EXPORTING

    content_type = 'application/json'.

* create Body for the HTTP Post request

CALL METHOD lo_http_client->request->set_cdata

  EXPORTING

    data = l_body.

lo_http_client->send(

    EXCEPTIONS

      http_communication_failure = 1

      http_invalid_state         = 2 ). "Send the HTTP request

lo_http_client->receive(

  EXCEPTIONS

    http_communication_failure = 1

    http_invalid_state         = 2

    http_processing_failed     = 3 ). "receive the response

l_result = lo_http_client->response->get_cdata( ).

This Succesfully posts my data to HANA, and i can read the status code in the response header to check the request status.

Do let me know if this was helpful, as usual i am always available in case you need any further clarifications.

Kind regards,

Vamsi


9 Comments
0 Kudos
Hi Vamsi,

 

I tried with your code everything is good but facing csrf token validation failed
vamsixk
Active Participant
0 Kudos
have you populated the csrf token(from the get request) in the post request? also you should use the same instance. if you instantiate a new client the x-csrf token becomes invalid. have you used the same instance?
0 Kudos
Hi Vamsi,

 

Cookies are missed so i have added that issue i resolved
naotoxxx
Participant
0 Kudos
Cool, thanks! , great post! i'm using as my guide , i'll be in touch in case something goes wrong 😄
naotoxxx
Participant

I have some questions:

l_body  is it my json?
l_query = im_query. , where is im_query declared so instead i did this l_query c_query.

i get this error :C "CSRF token validation failed" when i gent the response

vamsixk
Active Participant
0 Kudos
i don't remember filling anything in the l_body. it was not required for my situation.

have you populated the csrf token(from the get request) in to the post request? also you should use the same instance. if you instantiate a new client the x-csrf token becomes invalid. have you used the same instance?

 

Kind regards,

Vamsi

 
0 Kudos
Hi Vamsi,

I am using the below code to access the authorization token.

but getting the error during receive command as below.

'SSL Peer Certificate Untrusted'.

how to resolve this issue .

can u help me asap on this.

Regards,

Manjunath

 


SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L0S31 {
font-style: italic;
color: #808080;
}
.L0S32 {
color: #3399FF;
}
.L0S33 {
color: #4DA619;
}
.L0S52 {
color: #0000FF;
}
.L0S55 {
color: #800080;
}
.L0S70 {
color: #808080;
}


lv_url 'https://empoweredbenefits-QA.apigee.net/oauth/client_credential/accesstoken?grant_type=client_credentials'.

* cl_http_client=>create_by_destination(
*    EXPORTING
*      destination              = 'EMPOWEREDBENEFITS'    " 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 ).

cl_http_client=>create_by_url(
EXPORTING url lv_url " oData service URL
IMPORTING client lo_http_client
EXCEPTIONS OTHERS ).

*  call method lo_http_client->request->set_method
*    exporting
*      method = 'POST'.

call method lo_http_client->request->set_version
exporting
version if_http_request=>co_protocol_version_1_0.

CALL METHOD lo_http_client->request->set_method
EXPORTING
method lo_http_client->request->co_request_method_get.


CALL METHOD lo_http_client->request->if_http_entity~set_content_type
EXPORTING
content_type =  'application/json'.

*  lo_http_client->request->set_header_field(
*      name = 'Content-Type'
*      value = 'application/json'
*      ).

CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name  'X-CSRF-Token'
value 'Fetch'.

 
vamsixk
Active Participant
0 Kudos
Hi Manjunath,

 

This seems to be an SSL certificate issue. When you use the create by destination method, you can define which SSL certificate is to be used (defined in the transaction STRUST-Your basis Team should be able to help). that is one way i know that can by pass this issue.

Maintain your URL in an RFC destination and try accessing it via that method rather than use Create_BY_URL.

Kind regards,

Vamsi
sergio_cifuentes
Participant
0 Kudos
Hi Vamsi, thanks for your blog it was very helpful, however I need help:

I'm getting the token with the get method but for some reason I'm getting this error in the post :

CSRF token validation failed

this is my code:
DATA: l_query  TYPE string,
l_body TYPE string,
l_token TYPE string,
l_result TYPE string.

DATA: lo_http_client TYPE REF TO if_http_client.

CONSTANTS: c_rfchana TYPE rfcdest VALUE 'ZC4C_WS_QUOTES', " RFC Destination
c_query TYPE string VALUE '/sap/byd/odata/v1/c4codataapi/SalesQuoteCollection'. " Entity name

* fetch X-CSRF token

* Create the HTTP CLient

CALL METHOD cl_http_client=>create_by_destination
EXPORTING
destination = c_rfchana
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 NOT sy-subrc IS INITIAL.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

"STEP 2: - Fill headers and set URI for GET Method

* create the URI for the client.
l_query = c_query.

CALL METHOD cl_http_utility=>set_request_uri
EXPORTING
request = lo_http_client->request
uri = l_query.

* update the HTTP Method

CALL METHOD lo_http_client->request->set_method
EXPORTING
method = lo_http_client->request->co_request_method_get.

* set Content type

CALL METHOD lo_http_client->request->if_http_entity~set_content_type
EXPORTING
content_type = 'application/json'.

* set header field for fetching X-CSRF token
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'x-csrf-token'
value = 'fetch'.

"STEP 3: - trigger the GET method

lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ). "send the http request

lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ). "receive the response

****GET x-csrf TOKEN from earlier response

CALL METHOD lo_http_client->response->get_header_field
EXPORTING
name = 'x-csrf-token'
RECEIVING
value = l_token.

"STEP 4: - Fill headers and Body for HTTP POST method

* Set X-CSRF- Token in the new request.

CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'x-csrf-token'
value = l_token.

* update the HTTP Method

CALL METHOD lo_http_client->request->set_method
EXPORTING
method = lo_http_client->request->co_request_method_post.

****content type

CALL METHOD lo_http_client->request->set_content_type
EXPORTING
content_type = 'application/json'.

* create Body for the HTTP Post request

l_body = | \{ | &&
| "ProcessingTypeCode": "AG", | &&
| "BuyerPartyID": "1000724", | &&
| "BuyerID": "LP03", | &&
| "SalesUnitPartyID": "1000", | &&
| "SalesOrganisationID": "1000", | &&
| "DivisionCode": "10", | &&
| "DistributionChannelCode": "Z1", | &&
| "ZIsExternal_SDK": true, | &&
| "DateTime": "2019-08-19T17:33:08.3299380Z", | &&
| "ValidFromDate":"2019-08-19T00:00:00", | &&
| "ValidToDate":"2019-08-29T00:00:00", | &&
| "SalesQuoteItem": [ | &&
| \{ | &&
| "ProductInternalID": "5500002", | &&
| "Quantity": "5", | &&
| "QuantityMeasureUnitCode": "EA", | &&
| "MainPrice": "14.44000000000000", | &&
| "MainPriceCurrencyCode": "GTQ", | &&
| "ZPorcentageDiscount_SDK": "-4.99000000000000", | &&
| "MainDiscount": "-4.99000000000000" | &&
| \} | &&
| ] | &&
| \} |.

"| "user":"{ sy-uname }", | &&

CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = l_body.

lo_http_client->send(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2 ). "send the http request

lo_http_client->receive(
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3 ). "receive the response

l_result = lo_http_client->response->get_cdata( ).

 

Regards,

Sergio Cifuentes
Labels in this area