62 · BAPI & RFC Integration

Configure RFC destinations via Cloud Connector, call BAPIs from CAP, handle the RETURN table, and commit transactions.

Episode 62 — BAPI & RFC via Cloud Connector

What you'll learn

Why this matters

Some critical SAP business logic is only available as BAPIs — not via OData. Payment posting, batch processing, complex material movements — these still route through RFC. Knowing how to call them from CAP keeps you unblocked when the API Hub doesn't have what you need.

RFC vs OData — when to choose RFC

Use OData Use BAPI/RFC
Standard CRUD, reporting Complex business transactions
Available on API Hub Business logic only in ABAP
Performance not critical Atomic multi-step operations
New S/4HANA systems Legacy ECC/S/4 on-prem
S/4HANA Cloud (no RFC) S/4HANA on-prem

S/4HANA Cloud Public Edition does not support RFC. RFC is for on-prem or private-cloud systems.

SAP Cloud SDK setup

npm install @sap-cloud-sdk/connectivity @sap-cloud-sdk/http-client
# For JCo/RFC: add the JCo client library (requires SAP SDK download)

RFC destination configuration

In SCC admin → Access Control → Cloud to On-Premise → Add:

Back-end Type:  SAP ABAP System
Protocol:       RFC
Internal Host:  sapgw00.corp.internal
Internal Port:  3300
Virtual Host:   sapgw00-virtual
Virtual Port:   3300

In BTP Cockpit → Destinations → New:

Name:              SAP_ECC_RFC
Type:              RFC
jco.client.r3name: ECC
jco.client.client: 100
jco.client.lang:   EN
jco.destination.pool_capacity: 5
Authentication:    BasicAuthentication
User:              BAPI_USER
Password:          ****
ProxyType:         OnPremise

Calling a BAPI via SAP Cloud SDK

// srv/legacy-service.js
const { executeHttpRequest } = require('@sap-cloud-sdk/http-client')
const { buildHeadersForDestination } = require('@sap-cloud-sdk/connectivity')

// For BAPIs, use the RFC function module API via SAP Cloud SDK RFC module
// (requires @sap/cloud-sdk-core with JCo support — enterprise license)

this.on('getCustomerCredit', async (req) => {
  const { customerId } = req.data

  // Direct BAPI call via Cloud SDK
  const result = await SoapRfcClient.execute({
    destination:    'SAP_ECC_RFC',
    functionModule: 'BAPI_CUSTOMER_GET_CREDIT',
    importing: {
      KUNNR: customerId.padStart(10, '0')   // ABAP convention: left-pad with zeros
    }
  })

  return {
    creditLimit:  result.EXPORTING.CREDIT_LIMIT,
    creditUsed:   result.EXPORTING.CREDIT_USED,
    currency:     result.EXPORTING.CURRENCY
  }
})

Simpler: BAPI via SAP Gateway (OData wrapper)

The preferred approach on modern systems is to call BAPI via SAP Gateway's OData wrapper:

ABAP BAPI → SAP Gateway (OData V2) → BTP Destination → CAP
# In ABAP developer tools, create a Gateway project that wraps the BAPI
# Then consume via cds import / odata-v2 connector (same as Lesson 61)

Error handling for RFC

try {
  const result = await rfcClient.execute({ functionModule: 'BAPI_ORDER_CREATE1', ... })

  // BAPI return messages are in RETURN table (not exceptions)
  const errors = result.TABLES.RETURN?.filter(r => r.TYPE === 'E' || r.TYPE === 'A')
  if (errors?.length > 0) {
    return req.reject(400, errors.map(e => e.MESSAGE).join('; '))
  }

  // Commit the BAPI work (required for state-changing BAPIs)
  await rfcClient.execute({ functionModule: 'BAPI_TRANSACTION_COMMIT' })

  return result

} catch (err) {
  if (err.rfcErrorCode) {
    // RFC-specific errors (connection, auth, etc.)
    console.error('RFC error:', err.rfcErrorCode, err.message)
    return req.reject(502, 'SAP system temporarily unavailable')
  }
  throw err
}

BAPI_TRANSACTION_COMMIT — the gotcha

Most state-changing BAPIs require an explicit commit:

// Step 1: Call the BAPI
await rfcClient.execute({ functionModule: 'BAPI_SALESORDER_CREATE', ... })

// Step 2: Check RETURN table for errors
// Step 3: Only commit if no errors
await rfcClient.execute({ functionModule: 'BAPI_TRANSACTION_COMMIT', importing: { WAIT: 'X' } })

Never skip the BAPI_TRANSACTION_COMMIT — the order won't be created.

Hands-on exercise

  1. Create an RFC destination in Cloud Connector pointing to a local ABAP system or sandbox
  2. Implement a getSystemInfo action that calls RFC_SYSTEM_INFO
  3. Parse the result and return the system ID and release
  4. Test error handling by temporarily breaking the RFC destination

Checkpoint ✓

Sign in for progress tracking & Q&A →