node-rfc

repository·main·Indexed 42 days ago

https://github.com/sap-archive/node-rfc

Asynchronous, non-blocking Node.js client and server bindings for the SAP NetWeaver RFC SDK. It enables Node.js applications to interact with ABAP business logic with automatic data type conversion, supporting both stateless and stateful connections, connection pooling, and RFC server implementation. Version 3.3.1 requires SAP NW RFC SDK 7.50 PL12.

Tokens
18.6K
Snippets
62
Records
77
Agent score
53%

What's inside node-rfc

  1. Overview of node-rfc

    main

    node-rfc provides asynchronous, non-blocking client and server bindings for the SAP NetWeaver RFC SDK in Node.js. It allows for direct consumption of ABAP business logic from Node.js and enables extending the ABAP ecosystem with Node.js capabilities.

    Key features include:

    • Based on the N-API standard.
    • Supports both stateless and stateful connections (multiple function calls in the same ABAP session).
    • Provides both Async and Callback APIs.
    • Automatic conversion between Node.js and ABAP datatypes.
    • Supports sequential and parallel calls using one or more clients.
    • Managed connections via a connection pool.
    • Throughput monitoring (requires SAP NWRFC SDK >= 7.53).
  2. Use the Connection Pool for managed clients

    main

    The Pool provides managed clients that cannot open or close their own connections. Instead, the pool manages the lifecycle of connections. Managed clients use acquire() to get a connection and release() to return it to the pool.

    When a connection is released, the pool decides whether to keep it open (if the number of ready connections is below the high threshold) or close it. The low threshold defines the minimum number of connections the pool should keep open to accelerate future acquire() requests.

    const pool = new Pool({
        connectionParameters: connParams,
        clientOptions: {}, // optional
        poolOptions: { low: 2, high: 4 }, // optional
    });
    
    // To increase ready connections manually:
    await pool.ready(5);
  3. Understand ABAP Function Module parameter mapping

    main

    When calling a Remote Enabled ABAP Function Module (RFM), parameters are mapped as follows:

    • ABAP Variables $\rightarrow$ Node.js variables.
    • ABAP Structures $\rightarrow$ Node.js objects (simple key-value pairs).
    • ABAP Tables $\rightarrow$ Node.js arrays of objects (where each object represents an ABAP structure row).

    Example mapping for STFC_STRUCTURE:

    • IMPORTSTRUCT (Structure) $\rightarrow$ Node.js Object
    • ECHOSTRUCT (Structure) $\rightarrow$ Node.js Object
    • RESPTEXT (Variable) $\rightarrow$ Node.js String
    • RFCTABLE (Table) $\rightarrow$ Node.js Array of Objects
  4. Map Node.js and ABAP data types

    main

    The node-rfc library automatically handles type conversion between Node.js and ABAP.

    Numeric Types

    • INT and FLOAT map to JavaScript Number.
    • BCD, DECF16, and DECF34 map to JavaScript String by default. You can use the bcd client option to represent these as Number or custom decimal objects (e.g., decimal.js).

    Binary Types

    • BYTE and XSTRING map to Node.js Buffer objects.

    Date/Time Types

    • DATE (DATS) and TIME (TIMS) map to JavaScript String by default. You can use the date and time client options to use custom Date/Time objects.
    • UTCLONG maps to a JavaScript String (initial value: 0000-00-00T00:00:00.0000000).
    /* Mapping Summary Reference */
    // Node.js -> ABAP
    // Number -> INT
    // String -> CHAR/STRING
    // Buffer -> BYTE/XSTRING
    // String/Function -> DATE/TIME (with options)
    // String/Number/Object -> FLOAT/BCD/DECF (with options)
  5. Use Direct vs Managed (Pooled) Clients

    main

    You can manage connections in two ways:

    1. Direct Client: Instantiated with a closed connection. You must manually call .open() and .close(). This is suitable for simple, sequential tasks but can be risky in multi-threaded environments (like express) due to how the underlying C++ memory handles are reused.
    2. Managed Client (Connection Pool): Instantiated via the Pool class. The pool manages connections for you. Use pool.acquire((client) => { ... }) to get an active connection. This is the recommended approach for multi-threaded or high-concurrency applications to avoid RFC_INVALID_HANDLE errors.

    Connection State:

    • client.alive: Returns true if the connection is open.
    • client.connectionHandle: Returns the unique RFC_CONNECTION_HANDLE pointer (non-zero if open, zero if closed).
    // Direct Client (Manual management)
    const connParams = { dest: "QI3" };
    const Client = require("node-rfc").Client;
    const client = new Client(connParams);
    console.log(client.alive); // false
    
    // Managed Client (via Pool)
    const Pool = require("node-rfc").Pool;
    const pool = new Pool({ connectionParameters: connParams });
    pool.acquire((client) => {
        console.log(client.alive); // true
    });
  6. Cancel ongoing RFC calls

    main

    You can cancel an ongoing RFC call via several methods:

    1. Explicitly: Call client.cancel(), pool.cancel(client), or addon.cancelClient(client).
    2. Timeout: Provide a timeout in clientOptions or as an option in the client.call() method. The call() timeout overrides the client-level timeout.

    When a cancellation occurs, the sapnwrfc:cancel event is raised, and the call will throw an error with codeString: 'RFC_CANCELED'.

    // Cancel via timeout in the call
    try {
      const result = await client.call("BAPI_USER_GET_DETAIL", { USERNAME: "DEMO" }, { timeout: 5 });
    } catch (err) {
      // err.codeString will be 'RFC_CANCELED' if timed out
    }
    
    // Explicit cancel
    await client.cancel();
  7. Build node-rfc from source

    main

    If a pre-built package is not available for your platform (highly recommended for Linux), you can build it from source. This requires the SAP NW RFC SDK to be installed first.

    Note: Building from source requires a Node.js release with a minimum N-API version compatible with the napi_versions property in package.json.

    git clone https://github.com/SAP/node-rfc.git
    cd node-rfc
    npm install
    npm run addon # rebuild native addon
    npm run ts    # rebuild typescript wrapper
  8. Authenticate with SNC using User PSE

    main

    SNC (Secure Network Communications) with User PSE uses a User Personal Security Environment (PSE) to open the connection and perform authentication in the NW ABAP backend.

    Note: This method is generally not recommended. See SAP Note 1028503.

    Configuration

    • SNC_LIB: Path to the security library (e.g., libsapcrypto.dll). This can also be set via the SNC_LIB environment variable.
    • SNC_PARTNERNAME: The SNC name of the partner.
    • ASHOST, SYSNR, CLIENT

    Prerequisites

    1. SAP Single Sign On must be configured on the client.
    2. The user must be logged in on a client.
    3. The SNC name must be configured for the ABAP user in the NW ABAP system (Transaction SU01).
    SNC_LIB=C:\Program Files\SAP\FrontEnd\SecureLogin\libsapcrypto.dll
    SNC_PARTNERNAME=p/secude:CN=QM7, O=SAP-AG, C=DE
    ASHOST=ldciqm7.wdf.sap.corp
    SYSNR=20
    CLIENT=715
  9. Authenticate with plain username and password

    main

    The simplest and least secure authentication method uses a direct username and password. This can be configured using connection parameters such as USER, PASSWD, ASHOST, SYSNR, CLIENT, and LANG.

    USER=demo
    PASSWD=welcome
    ASHOST=10.68.110.51
    SYSNR=00
    CLIENT=620
    LANG=EN
  10. Configure the NODE_RFC_MODULE_PATH environment variable

    main

    The NODE_RFC_MODULE_PATH environment variable allows you to explicitly specify the path to the node_modules/node-rfc directory. This is useful if you need to point directly to the module path instead of relying on the default node-gyp-build resolution (which typically uses path.resolve(__dirname, "..")).

    # Using a .env file
    NODE_RFC_MODULE_PATH=./node_modules/node-rfc
  11. Invoke ABAP Function Modules

    main

    Once a client is connected, you can consume ABAP Remote-Enabled Function Modules (RFMs) using three patterns:

    1. Async/Await: The modern standard for clean asynchronous code.
    2. Promises: Using .then() and .catch() chains.
    3. Callbacks: The traditional pattern using client.invoke(name, params, callback).

    Note: For the callback pattern, use client.connect(callback) to ensure the connection is open before invoking.

    // Async/Await
    await client.open();
    let result = await client.call("STFC_STRUCTURE", { IMPORTSTRUCT: { ... } });
    
    // Promise
    client.open()
        .then(() => client.call("STFC_STRUCTURE", { ... }))
        .then(result => console.log(result));
    
    // Callback
    client.connect((err) => {
        if (err) return console.error(err);
        client.invoke("STFC_STRUCTURE", { ... }, (err, result) => {
            if (err) return console.error(err);
            console.log(result);
        });
    });