Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
Srdjan
Product and Topic Expert
Product and Topic Expert
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 abap CLI utility helps here, by generating a NodeJS source code for a given ABAP RFM call. All data structures are exposed, with metadata information and default technical initialisers, 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 of your test system

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

Then you can invoke the abap CLI for any remote enabled function module, to create the NodeJS call template of that function module in your backend system:
$ npm -g abap-api-tools

$ abap call MME BAPI_SALESORDER_CREATEFROMDAT2

The output for BAPI_SALESORDER_CREATEFROMDAT2 is echoed to console and, if the -s switch added, saved in a single local file. The full output ("call template") 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 call template output. If the LOGIC_SWITCH parameter 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 initialisation 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.
12 Comments