Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 

Introduction

SAP XI (PI/PO) developers and ABAP developers have traditionally collaborated with ease, thanks to ABAP Proxy — a convenient, well-established way to build SAP interfaces. However, when SAP Integration Suite enters the picture, that convenience quickly fades. Connectivity between ABAP systems and Integration Suite introduces a layer of complexity that many developers find challenging to navigate.

While several blogs already explain how to invoke an iFlow from an ABAP program, they largely stop there — none of them establish a central, reusable connectivity mechanism between an SAP NetWeaver application and Integration Suite. As a result, developers often end up rebuilding the same connectivity logic, again and again, for every single interface.

I saw an opportunity to bridge this gap between ABAP developers and Integration Suite developers. Instead of letting connectivity logic be reinvented for each interface, I designed a unified, pre-defined approach for invoking iFlows — one that could be reused consistently across the landscape. 

 

Business Requirement

You want to create an interface from a NetWeaver-based application to SAP Integration Suite, using an HTTPS sender adapter on the iFlow side and any receiver adapter of your choice.

 

Prerequisites

Before getting started, here are a couple of assumptions:

  1. SAP Integration Suite service is already activated on BTP.
  2. An iFlow with an HTTPS sender adapter (address: /demo_iflow, User role: ESBMessaging.send) has already been created and deployed. 

With these in place, let's get started.

 

Step 1: Establish Connectivity

a. Create a PI Runtime Instance in BTP

At the subaccount level in BTP, create a PI Runtime service instance.

sagarpatkar_0-1789126371130.png

sagarpatkar_1-1789126731630.png

b. Create a Service Key

Within the same subaccount, create a service key for the PI Runtime instance.

This key provides four key values: clientid, clientsecret, tokenurl, and url — you'll need these in the next steps.

c. Create an RFC Destination in NetWeaver (SM59)

Instead of hardcoding integration suite related connectivity details in your ABAP program, create a remote destination via transaction SM59:

Field Value

Hosturl from the service key
Port / Proxy detailsConsult your Basis team
Userclientid from the service key
Passwordclientsecret from the service key

Note: SSL configuration via STRUST is also required for this connection to work. This typically needs to be handled by your Basis team.

Host = url 

sagarpatkar_0-1789125009425.png

User = clientid , Password = clientsecret

sagarpatkar_1-1789125147094.png

Note:

1. To ensure that the connection is working fine, put the endpoint of iFlow in Host and perform connection test. Once validated replace it with only the url from service key. With this url the connection test will fail (status code 404) but it is ok as it will help us use the same destination for multiple iFlows programmatically.

2. This task has to be performed by basis team in every environment such as dev, qa, prd etc. 

 

Step 2: Create a Reusable ABAP Utility

To avoid repeating this code for every interface, the next step is to encapsulate it into a single, reusable ABAP class — one that any developer can simply call, passing in the iFlow-specific details (endpoint, payload, headers, method etc.), without worrying about authentication or connectivity.

Here's the source code for the ABAP class:

class ZCL_CPI_HTTP_SENDER definition
  public
  create public .

public section.

  methods CONSTRUCTOR
    importing
      !IV_URI type STRING optional
      !IV_RFCDEST_ISUITE type RFCDEST default 'INTEGRATION_SUITE'
    exceptions
      EX_NOT_LIVE .
  methods INVOKE_CPI_SYNC
    importing
      !IT_HTTP_HDR type TIHTTPNVP optional
      !IV_HTTP_METHOD type STRING default IF_HTTP_ENTITY=>CO_REQUEST_METHOD_POST
    exporting
      !ES_DATA_IN type DATA
      !EV_HTTP_RESP type CHAR3
    exceptions
      HTTP_COMMUNICATION_FAILURE .
  methods PREPARE_JSON
    importing
      !IV_DATA type DATA
      !IV_COMPRESS type /UI2/CL_JSON=>BOOL default ABAP_FALSE
      !IV_PRETTY_NAME type /UI2/CL_JSON=>PRETTY_NAME_MODE default /UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE
      !IV_ASSOC_ARRAYS type /UI2/CL_JSON=>BOOL default ABAP_FALSE
      !IV_NUMC_AS_STRING type /UI2/CL_JSON=>BOOL default ABAP_TRUE
      !IT_NAME_MAPPINGS type /UI2/CL_JSON=>NAME_MAPPINGS optional .
protected section.
private section.

  data MT_NAME_MAPPINGS type /UI2/CL_JSON=>NAME_MAPPINGS .
  data MV_REQ_BODY_JSON type STRING .
  data MV_URI type STRING .
  data MO_HTTP_CLIENT type ref to IF_HTTP_CLIENT .

  methods IS_STATUS_OK
    importing
      !IV_RETURN_STATUS type I
    returning
      value(RV_OK) type BOOLEAN .
ENDCLASS.



CLASS ZCL_CPI_HTTP_SENDER IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_CPI_HTTP_SENDER->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_URI                         TYPE        STRING(optional)
* | [--->] IV_RFCDEST_ISUITE              TYPE        RFCDEST (default ='INTEGRATION_SUITE')
* | [EXC!] EX_NOT_LIVE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD CONSTRUCTOR.

      CALL METHOD cl_http_client=>create_by_destination
        EXPORTING
          destination              = iv_rfcdest_isuite
        IMPORTING
          client                   = mo_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 sy-subrc EQ 0 AND mo_http_client IS BOUND.
        cl_http_utility=>set_request_uri(
        EXPORTING
         request = mo_http_client->request
         uri     = iv_uri ).
      ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_CPI_HTTP_SENDER->INVOKE_CPI_SYNC
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_HTTP_HDR                    TYPE        TIHTTPNVP(optional)
* | [--->] IV_HTTP_METHOD                 TYPE        STRING (default =IF_HTTP_ENTITY=>CO_REQUEST_METHOD_POST)
* | [<---] ES_DATA_IN                     TYPE        DATA
* | [<---] EV_HTTP_RESP                   TYPE        CHAR3
* | [EXC!] HTTP_COMMUNICATION_FAILURE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD INVOKE_CPI_SYNC.

    DATA: lv_response_json TYPE string,
          lo_response      TYPE REF TO if_rest_entity,
          lv_raise_error   TYPE boolean.

    CHECK mo_http_client IS BOUND.

    mo_http_client->request->set_method( iv_http_method ).

    IF mv_req_body_json IS NOT INITIAL.
      mo_http_client->request->set_cdata( EXPORTING data = mv_req_body_json  ).
    ENDIF.

    IF it_http_hdr IS NOT INITIAL.
      mo_http_client->request->set_header_fields( it_http_hdr ).
    ENDIF.

    mo_http_client->send(
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      http_invalid_timeout       = 4 ).
    IF sy-subrc EQ 0.

      mo_http_client->receive(
       EXCEPTIONS
         http_communication_failure = 1
         http_invalid_state         = 2
         http_processing_failed     = 3 ).
      IF sy-subrc EQ 0.

        " Get string data
        mo_http_client->response->get_status( IMPORTING code   = DATA(lv_code) ).
        ev_http_resp = lv_code.
        IF is_status_ok( lv_code ) EQ abap_true.
          DATA(lo_rest_client) = NEW cl_rest_http_client( io_http_client = mo_http_client  ).
          IF lo_rest_client IS BOUND.
            lo_response = lo_rest_client->if_rest_client~get_response_entity( ).
            IF lo_response IS BOUND.
              lv_response_json = lo_response->get_string_data( ).
              IF lv_response_json IS NOT INITIAL.
                CALL METHOD /ui2/cl_json=>deserialize
                  EXPORTING
                    json          = lv_response_json
                    pretty_name   = /ui2/cl_json=>pretty_mode-camel_case
*                   assoc_arrays  = C_BOOL-FALSE
*                   assoc_arrays_opt = C_BOOL-FALSE
                    name_mappings = mt_name_mappings
*                   conversion_exits = C_BOOL-FALSE
*                   hex_as_base64 = C_BOOL-TRUE
                  CHANGING
                    data          = es_data_in.
              ENDIF.
            ENDIF.
          ENDIF.
        ELSE.
          lv_raise_error = abap_true.
        ENDIF.

        CALL METHOD mo_http_client->close
          EXCEPTIONS
            http_invalid_state = 0
            OTHERS             = 0.

      ELSE.
        lv_raise_error = abap_true.
      ENDIF.

    ELSE.
      lv_raise_error = abap_true.
    ENDIF.

    IF lv_raise_error = abap_true.
      RAISE http_communication_failure.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_CPI_HTTP_SENDER->IS_STATUS_OK
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_RETURN_STATUS               TYPE        I
* | [<-()] RV_OK                          TYPE        BOOLEAN
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD IS_STATUS_OK.

    CLEAR rv_ok.
    IF iv_return_status GE 200 AND iv_return_status LE 299.   " http response status 200-299 indicate success
      rv_ok = abap_true.
    ENDIF.

  ENDMETHOD.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_CPI_HTTP_SENDER->PREPARE_JSON
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_DATA                        TYPE        DATA
* | [--->] IV_COMPRESS                    TYPE        /UI2/CL_JSON=>BOOL (default =ABAP_FALSE)
* | [--->] IV_PRETTY_NAME                 TYPE        /UI2/CL_JSON=>PRETTY_NAME_MODE (default =/UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE)
* | [--->] IV_ASSOC_ARRAYS                TYPE        /UI2/CL_JSON=>BOOL (default =ABAP_FALSE)
* | [--->] IV_NUMC_AS_STRING              TYPE        /UI2/CL_JSON=>BOOL (default =ABAP_TRUE)
* | [--->] IT_NAME_MAPPINGS               TYPE        /UI2/CL_JSON=>NAME_MAPPINGS(optional)
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD PREPARE_JSON.

* Serialize proxy message into json
    CALL METHOD /ui2/cl_json=>serialize
      EXPORTING
        data           = iv_data
        compress       = iv_compress
        pretty_name    = iv_pretty_name
        numc_as_string = iv_numc_as_string
      RECEIVING
        r_json         = mv_req_body_json.

  ENDMETHOD.
ENDCLASS.

 

Step: 3 Create ABAP program for invoking the iFlow

Here is a sample program simply sending an internal table ls_out-lines with sample headers lt_http_hdr to the iFlow

*&---------------------------------------------------------------------*
*& Report ZCPI_DEMO_HTTP_SEND
*&---------------------------------------------------------------------*
REPORT zcpi_demo_http_send.

TYPES: BEGIN OF ty_msg,
         lines TYPE /bofu/t_demo_bupa_id,
       END OF ty_msg.

DATA: lv_http_resp   TYPE char3,
      ls_http_hdr    TYPE ihttpnvp,
      lo_http_sender TYPE REF TO zcl_cpi_http_sender,

      ls_out         TYPE ty_msg,       " has to be a structure, type can be any (ty_msg is only for demo purpose)
      lt_http_hdr    TYPE tihttpnvp.    " can contain any headers you want to send to the iFlow

CONSTANTS:
  lc_uri     TYPE  string VALUE '/http/demo_iflow',     " address on https sender adapter
  lc_rfcdest TYPE  rfcdest VALUE 'INTEGRATION_SUITE'.   " name of RFC destination for integration suite

ls_out-lines = VALUE /bofu/t_demo_bupa_id( ( bupa_id = 'demo line 1' ) ( bupa_id = 'demo line 2' ) ( bupa_id = 'demo line 3' ) ).

TRY.

    CREATE OBJECT lo_http_sender EXPORTING iv_uri = lc_uri iv_rfcdest_isuite = lc_rfcdest.

* Prepare headers for the http request
    ls_http_hdr-name = 'itfName'.
    ls_http_hdr-value = 'Interface_XXX'.
    APPEND ls_http_hdr TO lt_http_hdr.

    CALL METHOD lo_http_sender->prepare_json EXPORTING iv_data = ls_out.

* Call iFlow
    CALL METHOD lo_http_sender->invoke_cpi_sync
      EXPORTING
        it_http_hdr                = lt_http_hdr
        iv_http_method             = if_http_entity=>co_request_method_get
      IMPORTING
*       es_proxy_in                = ls_response
        ev_http_resp               = lv_http_resp
      EXCEPTIONS
        http_communication_failure = 1
        OTHERS                     = 2.

  CATCH cx_root.

ENDTRY.

 

Conclusion

By establishing this centralized connectivity and building a reusable ABAP utility around it, we unlock several key benefits:

  1. Clear separation of duties — Basis, ABAP developers, and Integration Suite developers can each focus on their own area of expertise, without stepping on each other's responsibilities or duplicating effort.

  2. Significant time savings — Connectivity and authentication logic is built once and reused everywhere, eliminating the need to reinvent it for every new interface.

  3. Sharper developer focus — ABAP developers can shift their attention back to where it truly belongs: building robust data extraction logic, without needing to worry about the underlying connectivity mechanics.

Ultimately, this approach turns a repetitive, error-prone task into a standardized, one-time setup — making integrations with SAP Integration Suite faster, more consistent, and far easier to maintain at scale.

1 Comment
Labels in this area