Skip to Content
Technical Articles

Calling ABAP from NodeJS even easier

Calling ABAP BAPIs and remote enabled function modules (RFMs) from NodeJS is already easy:

const nodeRfc = require('node-rfc');
const pool = new nodeRfc.Pool({ connectionParameters: { dest: "MME" }});

(async () => {
    try {
        const client = await pool.acquire();

        const result = await client.call("BAPI_USER_GET_DETAIL", {
            USERNAME: "DEMO",
        });

        console.log(result);
    
    } catch (err) {
        console.error(err);
    }
})();

In this particular case, BAPI returns the information about ABAP user, based on one single input parameter, the USERNAME variable.

RFM input/output parameters can be also structures and tables,with hundred or more data fields. Some parameters may be mandatory, others are optional. Some variables, or structure/table fields may have ABAP Conversion Exits, which are not automatically triggered in RFC communication. RFM may return errors for the same input parameters which do work in ABAP transactions, like SE37 for example (seeĀ  206068 – Error when calling a BAPI from an external RFC client).

Assuming the Conversion Exits are fixed on ABAP side, complex BAPIs and RFMs parameters’ can be a challenge for NodeJS developer. One has to check which fields are mandatory, which default values used for optional fields, field technical format and so on.

The rfmcall utility helps here by generating a NodeJS source code for a given ABAP RFM call, exposing all data structures, with relevant metadata information and default technical initializers, at field level.

Let try it with one complex RFM, like BAPI_SALESORDER_CREATEFROMDAT2 for example. First create the sapnwrfc.ini file, with the destination and connection parameters for your test system

sapnwrfc.ini

DEST=MME
USER=demo
PASSWD=welcome
ASHOST=myhost
SYSNR=00
CLIENT=620
LANG=EN

Then you can invoke the fmcall for any remote enabled function module in your backend system:

$ npm install rfmcall

$ rfmcall MME BAPI_SALESORDER_CREATEFROMDAT2

The output for BAPI_SALESORDER_CREATEFROMDAT2 is echoed to console and can be saved in a single local file. The full output has ca 1,300 lines of code, structured as follows:

The file starts with the top-level RFM call structure, with optional parameters commented out, using only mandatory parameters ORDER_HEADER_IN and ORDER_PARTNERS:

//
// BAPI_SALESORDER_CREATEFROMDAT2
//

let params = {

  // IMPORT PARAMETERS

  ORDER_HEADER_IN                  :   {}, // BAPISDHD1 Order Header
  //BEHAVE_WHEN_ERROR              :   "", // CHAR (1) Error Handling
  //BINARY_RELATIONSHIPTYPE        :   "", // CHAR (4) Binary Relationship Type (Private)
  //CONVERT                        :   "", // CHAR (1) Conversion of Partner Function + Order Type
  //INT_NUMBER_ASSIGNMENT          :   "", // CHAR (1) Internal Item Number Assignment
  //LOGIC_SWITCH                   :   {}, // BAPISDLS Internal Control Parameter
  //ORDER_HEADER_INX               :   {}, // BAPISDHD1X Sales Order Check List
  //SALESDOCUMENTIN                :   "", // CHAR (10) ALPHA=ALPHA Sales and Distribution Document Number
  //SENDER                         :   {}, // BAPI_SENDER Logical System - Sender
  //TESTRUN                        :   "", // CHAR (1) Test Run

  // TABLE PARAMETERS

  ORDER_PARTNERS                   :   [], // BAPIPARNR Document Partner
  //EXTENSIONEX                    :   [], // BAPIPAREX Reference Structure for BAPI Parameters ExtensionIn/ExtensionOut
  //EXTENSIONIN                    :   [], // BAPIPAREX Customer Enhancement for VBAK, VBAP, VBEP
  //ORDER_CCARD                    :   [], // BAPICCARD Credit Card Data
  //ORDER_CFGS_BLOB                :   [], // BAPICUBLB Configuration: BLOB Internal Data (SCE)
  //ORDER_CFGS_INST                :   [], // BAPICUINS Configuration: Instances
  //ORDER_CFGS_PART_OF             :   [], // BAPICUPRT Configuration: Part-of Specifications
  //ORDER_CFGS_REF                 :   [], // BAPICUCFG Configuration: Reference Data
  //ORDER_CFGS_REFINST             :   [], // BAPICUREF Configuration: Reference Item / Instance
  //ORDER_CFGS_VALUE               :   [], // BAPICUVAL Configuration: Characteristic Values
  //ORDER_CFGS_VK                  :   [], // BAPICUVK Configuration: Variant Condition Key
  //ORDER_CONDITIONS_IN            :   [], // BAPICOND Conditions
  //ORDER_CONDITIONS_INX           :   [], // BAPICONDX Conditions Checkbox
  //ORDER_ITEMS_IN                 :   [], // BAPISDITM Item Data
  //ORDER_ITEMS_INX                :   [], // BAPISDITMX Item Data Checkbox
  //ORDER_KEYS                     :   [], // BAPISDKEY Output Table of Reference Keys
  //ORDER_SCHEDULES_IN             :   [], // BAPISCHDL Schedule Line Data
  //ORDER_SCHEDULES_INX            :   [], // BAPISCHDLX Checkbox Schedule Line Data
  //ORDER_TEXT                     :   [], // BAPISDTEXT Texts
  //PARTNERADDRESSES               :   [], // BAPIADDR1 BAPI Reference Structure for Addresses (Org./Company)
  //RETURN                         :   [], // BAPIRET2 Return Messages
};

result = await client.call("BAPI_SALESORDER_CREATEFROMDAT2", params);

Parameters initialised with NodeJS scalars, like integer zero or empty string are ABAP variables, like BEHAVE_WHEN_ERROR. Parameters initialised with empty NodeJS structures are ABAP structures (ORDER_HEADER_IN) and those initialised with empty NodeJS arrays are ABAP tables, like ORDER_PARTNERS.

If Conversion-Exit is attached to data field, the ALPHA comment with Conversion-Exit name is added in comment field, just as a reminder for ABAP developer to add the Conversion Exit in ABAP RFM wrapper. This can be also helpful in troubleshooting.

The first section covers all RFM parameters and ends with the RFM call statement.

Structure and table parameters are in detail covered in the rest of rfmcall output. If the LOGIC_SWITCH structure in required in RFM call, you can search for the BAPISDLS type given in a LOGIC_SWITCH parameter comment and find the field level initialization of that structure parameter:

// LOGIC_SWITCH BAPISDLS Internal Control Parameter

let LOGIC_SWITCH   =   {}; // BAPISDLS Internal Control Parameter

let BAPISDLS = {
  ADDR_CHECK       :   "", // CHAR (1) Single-Character Flag
  ATP_WRKMOD       :   "", // CHAR (1) ATP session: Pick up result / new determination APO-ATP
  COND_HANDL       :   "", // CHAR (1) Selection: Condition lines handling (SD document change)
  NOSTRUCTURE      :   "", // CHAR (1) Checkbox
  PRICING          :   "", // CHAR (1) Pricing type
  SCHEDULING       :   "", // CHAR (1) Single-Character Flag
};

The same with the credit card table parameter ORDER_CCARD of the BAPICCARD data type:

// ORDER_CCARD BAPICCARD Credit Card Data

let ORDER_CCARD    =   []; // BAPICCARD Credit Card Data

let BAPICCARD = {
  AMOUNTCHAN      :   "", // CHAR (1) Payment cards: Amount changed
  AUTHORTYPE      :   "", // CHAR (1) Payment cards: Authorization type
  CC_LIMITED      :   "", // CHAR (1) Payment cards: Limit amount
  CC_SEQ_NO       :   "", // CHAR (10) Payment cards: Payment card suffix
  DATAORIGIN      :   "", // CHAR (1) Payment cards: Entry mode
  PRE_AUTH        :   "", // CHAR (1) Payment cards: Preauthorization
  RADRCHECK1      :   "", // CHAR (4) Payment Cards: Result of Address Check (Address Result)
  RADRCHECK2      :   "", // CHAR (4) Payment Cards: Result of Address Check (Address Approval)
  RADRCHECK3      :   "", // CHAR (4) Payment Cards: Result of Address Check (ZIP Code Result)
  RCARDCHECK      :   "", // CHAR (4) Payment cards: Result of card check (response code)
};

The utility can be used independent of the Fundamental Library for ABAP, to accelerate the development and troubleshooting of NodeJS applications working directly with ABAP data. It works with the any ABAP BAPI or RFM and the output can be used also for Python or Java applications, with minimum post-processing in a text-editor.

Feel free to try, feedback welcome.

2 Comments
You must be Logged on to comment or reply to a post.