Skip to Content
Author's profile photo Vamsi Krishna C V

Consume Odata Service in ABAP CL_HTTP_CLIENT->CREATE_BY_DESTINATION (HTTP Post Method)

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 Schmidt and Ashwin Dutt 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


Assigned Tags

      9 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Divya Vemulapati
      Divya Vemulapati

      Hi Vamsi,

       

      I tried with your code everything is good but facing csrf token validation failed

      Author's profile photo Vamsi Krishna C V
      Vamsi Krishna C V
      Blog Post Author

      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?

      Author's profile photo Divya Vemulapati
      Divya Vemulapati

      Hi Vamsi,

       

      Cookies are missed so i have added that issue i resolved

      Author's profile photo Naoto Amari
      Naoto Amari

      Cool, thanks! , great post! i'm using as my guide , i'll be in touch in case something goes wrong ūüėÄ

      Author's profile photo Naoto Amari
      Naoto Amari

      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

      Author's profile photo Vamsi Krishna C V
      Vamsi Krishna C V
      Blog Post Author

      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

       

      Author's profile photo Manjunath Bannur
      Manjunath Bannur

      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 = 1 ).

      *  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'.

       

      Author's profile photo Vamsi Krishna C V
      Vamsi Krishna C V
      Blog Post Author

      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

      Author's profile photo Sergio Cifuentes
      Sergio Cifuentes

      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