Skip to Content
Technical Articles
Author's profile photo Srdjan Boskovic

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

Assigned Tags

      12 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Stijn Mertens
      Stijn Mertens

      It's nice that this is available, but from an architecture point of view I would still prefer to wrap the function in an oData service. Or am I missing some needs?

      Anyway, good to know that this is also possible. Thanks for the insights!

      Author's profile photo Srdjan Boskovic
      Srdjan Boskovic
      Blog Post Author

      The utility is for people already using node-rfc, in scenarios like other ABAP Connectors::

      https://support.sap.com/en/product/connectors.html

      Also experimenting with low-code ABAP web applications, with new and old systems, hybrid systems etc:

      https://blogs.sap.com/2020/08/23/fundamental-library-for-abap/

      Author's profile photo mahesh zeple
      mahesh zeple

      Hello Srdjan Boskovic,

      I am trying to use this in my Cloud Application Programming Model project, trying to call BAPI from SRV layer.

      When i tried deploying my MTAR file to Cloud Foundry, its giving error - npm ERR! Failed at the node-rfc@2.4.0 install script.

      When i checked some other blogs, saw one comment from you -

      Please try with the latest node-rfc 2.4.0, not the 2.3.0 version.

      Which is your node version?

      The log shows 12.14, which is not supported. Should be at least 12.17: https://github.com/SAP/node-rfc/blob/master/package.json#L11

      My Node version is -

      User: TestProj $ node -v
      v10.23.1
      user: TestProj $

      Is there any workaround for this to work with lower node versions ? I doubt if we will be able to upgrade node version.

       

      Regards,

      Mahesh Z.

      Author's profile photo Srdjan Boskovic
      Srdjan Boskovic
      Blog Post Author

      Hi mahesh zeple ,

      the node-rfc works also on lower LTS versions, only the build from source is restricted by N-API support matrix to

        "engines": {
          "node": "~10 >=10.23 || ~12 >=12.17 || >= 14.0"

      Unless the engine-strict config flag set in your environment, the installation is not affected by this restriction. 

      The node-rfc is not supported in Cloud Foundry environment and there is one open improvement request: https://influence.sap.com/sap/ino/#/idea/262169

      The error might be therefore related to something else and it would help if you can share the error log.

      Just tested with 10.23.1 and here the log:

      npm i node-rfc --save                                                                                                                      
      
      > node-rfc@2.4.0 preinstall /Users/d037732/tmp/node_modules/node-rfc
      > npm install cmake-js prebuild-install prebuild node-addon-api
      
      > node-rfc@2.4.0 install /Users/d037732/tmp/node_modules/node-rfc
      > prebuild-install --tag-prefix -r napi || cmake-js rebuild
      
      npm notice created a lockfile as package-lock.json. You should commit this file.
      npm WARN tmp@1.0.0 No description
      npm WARN tmp@1.0.0 No repository field.
      
      + node-rfc@2.4.0
      added 3 packages from 75 contributors and audited 3 packages in 20.377s
      found 0 vulnerabilities
      
      ~/tmp ❯❯❯ node -p "require('node-rfc').environment"                                                                                                  
      
      { platform: { name: 'darwin', arch: 'x64', release: '20.3.0' },
        env: { SAPNWRFC_HOME: '/usr/local/sap/nwrfcsdk', RFC_INI: '' },
        versions:
         { http_parser: '2.9.4',
           node: '10.23.1',
           v8: '6.8.275.32-node.59',
           uv: '1.34.2',
           zlib: '1.2.11',
           brotli: '1.0.7',
           ares: '1.15.0',
           modules: '64',
           nghttp2: '1.41.0',
           napi: '7',
           openssl: '1.1.1i',
           icu: '64.2',
           unicode: '12.1',
           cldr: '35.1',
           tz: '2019c' },
        noderfc:
         { version: '2.4.0',
           nwrfcsdk: { major: 7500, minor: 0, patchLevel: 7 } } }

       

      Author's profile photo mahesh zeple
      mahesh zeple

      Hello,

       

      Yes , I am also taking somewhat similar error when i run it locally.

       

      Thanks ,

      Mahesh Z.

      Author's profile photo Srdjan Boskovic
      Srdjan Boskovic
      Blog Post Author

      Is hard to guess without the error log/output and more info on environment. You can also create a GitHub issue, with more details there.

      Author's profile photo mahesh zeple
      mahesh zeple

      Hello Srdjan,

       

      Getting below error while starting the localhost from run config itself -

       

      [ERROR] libsapnwrfc.so: cannot open shared object file: No such file or directory
      environment: {
      "platform": {
      "name": "linux",
      "arch": "x64",
      "release": "5.4.0-5-cloud-amd64"
      },
      "env": {
      "SAPNWRFC_HOME": "",
      "RFC_INI": ""
      },
      "versions": {
      "node": "14.16.0",
      "v8": "8.4.371.19-node.18",
      "v8": "8.4.371.19-node.18",
      "uv": "1.40.0",
      "zlib": "1.2.11",
      "brotli": "1.0.9",
      "ares": "1.16.1",
      "modules": "83",
      "nghttp2": "1.41.0",
      "napi": "7",
      "llhttp": "2.1.3",
      "openssl": "1.1.1j",
      "cldr": "37.0",
      "icu": "67.1",
      "tz": "2020a",
      "unicode": "13.0"
      }
      }
      at Object.Module._extensions..node (internal/modules/cjs/loader.js:1122:18)
      at Module.load (internal/modules/cjs/loader.js:928:32)
      at Function.Module._load (internal/modules/cjs/loader.js:769:14)
      at Module.require (internal/modules/cjs/loader.js:952:19)
      at require (internal/modules/cjs/helpers.js:88:18)
      at Object. (/home/user/projects/emailpoc/node_modules/node-rfc/lib/wrapper/noderfc-bindings.js:36:49)
      at Module._compile (internal/modules/cjs/loader.js:1063:30)
      at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
      at Module.load (internal/modules/cjs/loader.js:928:32)
      at Function.Module._load (internal/modules/cjs/loader.js:769:14)
      at Module.require (internal/modules/cjs/loader.js:952:19)
      at require (internal/modules/cjs/helpers.js:88:18)
      at Object. (/home/user/projects/emailpoc/node_modules/node-rfc/lib/index.js:16:14)
      at Module._compile (internal/modules/cjs/loader.js:1063:30)
      at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
      at Module.load (internal/modules/cjs/loader.js:928:32)
      Process exited with code 1

       

      Thanks ,
      Mahesh Zeple.

      Author's profile photo Srdjan Boskovic
      Srdjan Boskovic
      Blog Post Author

      Did you install SAP NWRFC SDK following the installtion guide: https://github.com/SAP/node-rfc/blob/main/doc/installation.md ?

      Author's profile photo kristan arcino
      kristan arcino

      is there a working github example? POST example seems like dangerous. How about bapi_salesorder_getlist example.

      Author's profile photo Srdjan Boskovic
      Srdjan Boskovic
      Blog Post Author

      Here it is: https://github.com/SAP-samples/node-rfc-samples/tree/main/integration/express

      Author's profile photo Piyush Gupta
      Piyush Gupta

      Hi,

      I am new to node.js and getting the following error while trying to run this.

      (node:2844) UnhandledPromiseRejectionWarning: TypeError: fs_1.default.rmSync is not a function
      at Object.rmDir (/Users/<user>/.nvm/versions/node/v12.18.4/lib/node_modules/abap-api-tools/dist/utils.js:69:18)
      at Backend.annotations_clean (/Users/<user>/.nvm/versions/node/v12.18.4/lib/node_modules/abap-api-tools/dist/backend.js:609:17)
      at Backend.parse (/Users/<user>/.nvm/versions/node/v12.18.4/lib/node_modules/abap-api-tools/dist/backend.js:346:18)
      at async CliHandler.run (/Users/<user>/.nvm/versions/node/v12.18.4/lib/node_modules/abap-api-tools/dist/abap.js:63:35)
      (node:2844) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
      (node:2844) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

      Any idea how this could be resolved?

      Author's profile photo Srdjan Boskovic
      Srdjan Boskovic
      Blog Post Author

      Hi,

      the issue is related to abap-api-tools.

      You can create an issue here: https://github.com/SAP/fundamental-tools/issues and describe steps how to reproduce.

      Kind regards, srdjan