Skip to Content

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


9 Comments
You must be Logged on to comment or reply to a post.
    • 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?

    • 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

  • 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

     

  • 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’.

     

    • 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

  • 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