Design an IFS integration middleware layer
Documentation-based guide draft · Reviewed against sources on 2026-09-27 · Not executed in an IFS environment. IFS references use 26R1 unless stated otherwise. Confirm available APIs, components, and permissions in your installed release.
Build a small local file worker that forwards an approved message to IFS and saves the response. This makes the middleware’s responsibilities concrete before you implement the same contract in WSO2, another integration platform, or a managed queue service.
Before you start
Section titled “Before you start”Install a supported Node.js version with built-in fetch. Prepare an approved HTTPS IFS inbound endpoint and an accepted JSON fixture. The worker below performs one attempt, saves a receipt, and does not automatically retry. It is a teaching worker, not a durable production queue.
1. Create the workspace and configuration
Section titled “1. Create the workspace and configuration”Create ifs-worker-lab, put the validated JSON message in message.json, and choose a stable messageId. Obtain a short-lived token for the intended service identity using authentication.
Set IFS_INBOUND_URL and IFS_ACCESS_TOKEN in your terminal/process environment through your approved local secret mechanism. Never commit them into the worker file. The endpoint must be fixed by configuration, not supplied by the message.
2. Implement a bounded sender
Section titled “2. Implement a bounded sender”Save send-once.mjs:
import { readFile, writeFile, access } from 'node:fs/promises';const [inputFile, receiptFile] = process.argv.slice(2);if (!inputFile || !receiptFile) throw new Error('Usage: node send-once.mjs input.json receipt.json');const endpoint = new URL(process.env.IFS_INBOUND_URL);if (endpoint.protocol !== 'https:') throw new Error('HTTPS endpoint required');const token = process.env.IFS_ACCESS_TOKEN;if (!token) throw new Error('Missing IFS_ACCESS_TOKEN');const text = await readFile(inputFile, 'utf8');if (Buffer.byteLength(text) > 65536) throw new Error('Lab message exceeds 64 KiB');const message = JSON.parse(text);if (!/^[A-Z0-9-]{1,64}$/.test(message.messageId ?? '')) throw new Error('Invalid messageId');try { await access(receiptFile); throw new Error('Receipt already exists: reconcile it before replay');} catch (error) { if (error.code !== 'ENOENT') throw error;}await writeFile(receiptFile, JSON.stringify({ messageId: message.messageId, state: 'attempt-started', at: new Date().toISOString()}), { flag: 'wx' });try { const response = await fetch(endpoint, { method: 'POST', redirect: 'error', signal: AbortSignal.timeout(15000), headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, body: text }); const body = await response.text(); await writeFile(receiptFile, JSON.stringify({ messageId: message.messageId, state: response.ok ? 'http-accepted' : 'http-rejected', status: response.status, body }, null, 2)); if (!response.ok) process.exitCode = 1;} catch (error) { await writeFile(receiptFile, JSON.stringify({ messageId: message.messageId, state: 'outcome-unknown', error: error.name }, null, 2)); throw error;}Keep the workspace private: the response may contain business data. The receipt is created before sending, so a second invocation using the same receipt path refuses to resubmit. This is a local guard, not a substitute for receiver-side idempotency or a shared production store.
3. Run one attempt and inspect both systems
Section titled “3. Run one attempt and inspect both systems”Run:
node send-once.mjs message.json receipt-LAB-051.jsonOpen the receipt. For http-accepted, follow the response’s message/status reference and verify the IFS business result. For http-rejected, diagnose the status/body. For outcome-unknown or attempt-started, search IFS by the original message reference before any replay.
4. Add transformation as a separate stage
Section titled “4. Add transformation as a separate stage”Keep the original message immutable. Write a pure mapping function that produces the receiver’s schema and test it with fixtures before the sender runs. Use XSLT for XML mappings or a tested Java/Node component for another format.
Save mapping version and message ID in production processing records. Avoid performing remote business writes inside a transformation; it makes replay and fault diagnosis harder.
5. Move the proven contract into your middleware platform
Section titled “5. Move the proven contract into your middleware platform”For WSO2 or another platform, configure a fixed endpoint, secure credential reference, schema validation, bounded timeout, persistent queue, and an error/reconciliation destination matching the states above. Use its supported runtime and deployment model; do not import an old connector merely because its name mentions IFS.
The production implementation needs atomic message claiming, persistent duplicate keys, token renewal, bounded response sizes, controlled retries, and concurrent-worker coordination. Prove each using the same fixtures rather than treating a successful container health check as business acceptance.
6. Verify replay and cleanup
Section titled “6. Verify replay and cleanup”Test invalid JSON, missing token, an HTTP rejection, timeout, and a second run with the same receipt filename. Confirm that the local replay guard blocks the second run and that no automatic retry occurs.
After collecting evidence, clear the token from the process environment, stop lab producers, and remove private receipts according to your retention rules. Revoke any dedicated lab credential. Leave unresolved receipts intact until their business outcome is reconciled.
Sources and scope
Section titled “Sources and scope”Older IFS Applications examples are historical context, not evidence of Cloud compatibility. No third-party code, screenshots, or downloadable workflows are reproduced.