Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CPI Integration Controller

Postman pre-request framework / controller for delivering documents asynchronously to SAP Cloud Integration Suite (CPI), considering different integration aspects for pushing interfaces / clients:

  • OAuth token handling
  • Full request snapshot queue
  • Idempotency via execution_history
  • Retry processing
  • Error logging
  • Mutex protection against rapid duplicate execution
  • Postman variable substitution in URL and body
  • Generated message GUID, SAP GUID, and timestamp variables
  • Canonical payload MD5 hashing with configurable dynamic-field masking
  • Duplicate suppression for successful and pending payloads
  • Manual cancellation of retry messages
  • Forced delivery mode that bypasses quality-of-service checks
  • OAuth token caching, expiry handling, and diagnostics
  • Retry counters and queue-size tracking

The controller is intended for a client-to-CPI integration where CPI accepts a document, places it on a JMS queue, and returns an HTTP status code, usually 202. It adds client-side delivery protection and diagnostics around the CPI endpoint.

Architecture

Client / Postman
    |
    | OAuth client-credentials token
    v
SAP CPI HTTPS endpoint
    |
    | Validate, correlate, enqueue
    v
CPI JMS queue / integration flow
    |
    v
SAP ERP processing

The Postman controller is src/pre_request.js.

GitHub Copilot repository instructions are in .github/copilot-instructions.md. Extended AI-agent guidance is in AGENTS.md.

API

The current development server is:

https://<cpi-rt-host>

The resource path is:

/http/<path>

Together, the request URL is:

https://<cpi-rt-host>/http/<path>

The API is asynchronous. A successful 202 Accepted means CPI accepted the message for queue processing; it does not mean that the downstream ERP posting has completed.

Quality of service

The framework currently implements a client-side ExactlyOnceInOrder policy. It uses one FIFO pending_messages queue, processes one queued message at a time, retries in queue order, and suppresses duplicates using the message GUID and canonical payload MD5.

Every CPI delivery includes:

SapQualityOfService: ExactlyOnceInOrder

This is a delivery contract between the client and CPI, not proof of end-to-end EOIO. SAP CPI does not currently provide full EOIO semantics for this integration. The framework cannot guarantee mathematical end-to-end exactly-once processing by itself: CPI/JMS and SAP ERP must honor the header, preserve correlation, and apply idempotent business processing. A lost response after CPI acceptance remains an ambiguity that must be handled by CPI/ERP idempotency.

Postman setup

  1. Create or import the CPI POST request in Postman.
  2. Copy the complete contents of src/pre_request.js into the request, folder, or collection Pre-request Script tab.
  3. Configure the active Postman environment with the variables below.
  4. Set the request body to the JSON payload expected by CPI.
  5. Use pm_log_level=history for normal operation or pm_log_level=verbose while diagnosing a delivery.

Required variables

Variable Purpose
baseUrl CPI host, for example https://<cpi-rt-host>
token_url OAuth token endpoint
client_id OAuth client ID
client_secret OAuth client secret

The request URL should include the complete CPI path, for example:

{{baseUrl}}/http/<path>

Optional variables

Variable Default / example Purpose
pm_log_level history history keeps output compact; verbose prints request/response diagnostics
dynamic_json_paths MessageHeader.UUID, Record_Data.item.alloc_nmbr JSON paths masked before the idempotency hash is calculated
cpi_host <cpihost> CPI monitoring-link host
erp_host <erphost> ERP monitoring-link host
erp_client <erpclient> ERP client used in the monitoring link
manual_cancel_msgid empty Cancels a currently queued retry message by GUID
manual_forced_sent false Sends the current message while bypassing duplicate/QoS checks

The controller generates these local variables for the request body:

Variable Meaning
my_guid Generated UUID with hyphens
sap_guid Generated UUID without hyphens, uppercase
ts Current UTC ISO timestamp

Example body references:

{
  "MessageHeader": {
    "UUID": "{{my_guid}}"
  },
  "Record_Data": [
    {
      "item": [
        {
          "alloc_nmbr": "{{ts}}"
        }
      ]
    }
  ]
}

Delivery behavior

The controller performs these operations for each execution:

  • Resolves Postman variables in the URL and raw request body.
  • Generates a message GUID, SAP GUID, and timestamp.
  • Gets or refreshes an OAuth client-credentials token.
  • Canonicalizes the JSON payload and calculates an MD5 idempotency hash.
  • Processes queued messages before the current main request.
  • Sends the current request through pm.sendRequest().
  • Stores failed deliveries as retryable queue entries.
  • Records execution history in the Postman environment.
  • Prints a compact execution table and CPI/ERP monitoring links.
  • Registers successful, failed, and skipped Postman test results.

Execution history

History is stored in the environment variable execution_history as JSON. Supported status types are:

  • SUCCESS: final successful delivery; the same hash is skipped later.
  • RETRY: delivery failed and the message is in the retry queue.
  • ERROR: treated as a retryable blocking failure.
  • CANCELLED: a queued retry was manually cancelled.
  • SKIPPED: duplicate or otherwise suppressed delivery.

The pending queue is stored in pending_messages as JSON. Each queued item contains the message GUID, payload hash, retry position, queue size, request method, headers, body, and URL metadata.

The actual URL used for a main delivery or retry is resolved from the current Postman request at send time. This allows a changed baseUrl or CPI path configuration to affect retries; the URL in the snapshot is retained as historical metadata.

Idempotency and dynamic fields

The controller sorts JSON object keys and masks dynamic fields before hashing. By default it masks:

MessageHeader.UUID
Record_Data.item.alloc_nmbr

This prevents a new GUID or timestamp from making an otherwise identical payload look new. Add or replace paths with dynamic_json_paths when other fields are generated dynamically.

Duplicate handling is intentionally conservative:

  • A successful hash is skipped.
  • A hash already pending in the queue is skipped.
  • A retry or error remains blocking until it succeeds or is manually cancelled.
  • A forced send bypasses these quality-of-service checks for the current message.

Manual operations

Cancel a retry

Set manual_cancel_msgid to the GUID of a message currently in pending_messages. Only messages with RETRY or ERROR history can be cancelled. Invalid cancellation attempts throw an error rather than silently changing state.

Force a message

Set manual_forced_sent=true for one execution. The flag is cleared by the script at startup. The current message bypasses duplicate and queue checks, and its success description records that it was forced. A forced failure is still queued for later retry.

Logging and tests

Normal logging prints the execution history table. Set pm_log_level=verbose to print:

  • Outgoing URL, method, headers, and body.
  • HTTP status, response headers, and response body.
  • Transport errors.
  • Retry position and queue size.

The controller uses pm.test() and pm.test.skip() directly. It does not rewrite pm.response: requests initiated with pm.sendRequest() do not populate Postman’s native response panel. This is required to catch both HTTP failures and transport failures before queuing them.

CPI integration considerations

  • Treat 202 Accepted as queue acceptance, not business completion.
  • Preserve the request GUID through CPI and ERP for end-to-end correlation.
  • Return the correlation header SapMessageIdEx where available.
  • Keep CPI endpoint paths stable and environment-specific through baseUrl.
  • Ensure OAuth scopes allow the CPI integration flow and keep client secrets out of collections and source control.
  • Make CPI validation errors distinguishable from transport or platform errors.
  • Configure CPI/JMS retry and dead-letter behavior separately from this client-side retry queue.
  • Avoid creating duplicate business documents in CPI when a client retry repeats an accepted message.
  • Monitor CPI message processing and ERP posting independently; an HTTP success does not prove ERP success.
  • Align timeout, retry delay, queue retention, and idempotency policy with CPI operational limits.

Validation

Validate the JavaScript syntax with:

node --check src/pre_request.js

Security

Do not commit real OAuth client secrets, access tokens, environment exports, execution history, or pending queue contents. Use Postman environments, secret variables, a CI secret store, or a vault for credentials.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages