cannectors

soap_call

Per-record SOAP enrichment with caching and merge strategies.

The soap_call filter sends a SOAP request for each record and merges the parsed SOAP response back into that record. It supports the same cache and merge strategy model as http_call, plus SOAP-specific XML body templating, WS-Security, and MTOM.

Minimal example

filters:
  - type: soap_call
    endpoint: https://soap.example.com/customers
    soapAction: urn:GetCustomer
    operation: GetCustomer
    body: |
      <m:GetCustomer xmlns:m="urn:customers">
        <m:CustomerId>{{ record.customerId }}</m:CustomerId>
      </m:GetCustomer>
    dataField: Envelope.Body.GetCustomerResponse.Customer
    mergeStrategy: append
    resultKey: customer

Options

propertytypedefaultdescription
typerequired
"soap_call"Module type discriminator. Must be `soap_call` for this module.
id
stringUnique identifier within the pipeline.
name
stringHuman-readable name.
description
string
enabled
booleantrueWhether module is active.
tags
array<string>
onError
string"fail"Default error action. Case-insensitive; normalized to lowercase by the runtime.
endpointrequired
stringSOAP endpoint URL. Templates are accepted; the final URL is validated at runtime after template resolution.
soapVersion
string"1.1"SOAP envelope and HTTP binding version.
1.11.2
soapAction
stringSOAP action. SOAP 1.1 sends this as the SOAPAction header; SOAP 1.2 sends it as a Content-Type action parameter.
operationrequired
stringLogical SOAP operation name.
bodyrequired
stringRaw XML body fragment. Templates ({{record.field}}) are XML-escaped at runtime.
array<object>Raw SOAP header XML fragments.
union (4 variants)HTTP transport authentication.
object
object
httpHeaders
map<string, string>Additional HTTP headers. Content-Type and SOAPAction are controlled by the SOAP version.
timeoutMs
integerRequest timeout in milliseconds. When omitted, each module applies its own runtime default.
mergeStrategy
string"merge"How to merge the call response with the input record. merge: deep-merge the response into the record. replace: overwrite the record's top-level keys with the response ones. append: nest the whole response under resultKey.
mergereplaceappend
resultKey
stringRecord key receiving the whole response with mergeStrategy: append. Required as soon as mergeStrategy is append, for the three call filters alike; ignored by the merge and replace strategies.
array<object>List of key configurations for extracting values from records and using them in request metadata.
object
dataField
stringField path to extract from the parsed SOAP response map before merge/replace/append. When omitted, the full parsed SOAP response is used.
object

Merge strategies

StrategyEffect
merge (default)Deep-merge response fields into the current record. Nested objects are merged; response values overwrite conflicts.
replaceOverlay SOAP response fields onto the current record. Existing fields not present in the response are preserved.
appendStore the SOAP response under resultKey.

append requires resultKey so the filter has a stable destination for the SOAP result — omitting it fails cannectors validate.

http_call, soap_call and sql_call share this contract — see merge contract of the call filters.

Selecting the response with dataField

dataField is a path into the parsed SOAP response (Envelope.Body.GetCustomerResponse.Customer). Repeated XML elements parse to a list, and that list reaches the record unchanged under resultKey — iterate it with loop. A path resolving to a scalar or to nothing is an error arbitrated by onError, not an enrichment.

This is a behavior change. A list response used to be wrapped under an implicit items key and a scalar under value — keys no pipeline ever declared. Both are gone: the list is the list, and a scalar is an error.

http_call follows the same rules — see selecting the response with dataField.

Caching

Use the cache block to deduplicate SOAP enrichment calls that would resolve to the same result:

cache:
  enabled: true
  maxSize: 1000
  ttlSeconds: 300
  key: "{{ record.customerId }}"

If cache.key is omitted, the resolved endpoint and operation shape are used as the cache identity. Set an explicit per-record key when the SOAP body varies by record.

The cache also outlives a run the same way it does for http_call and sql_call: on a scheduled pipeline, ttlSeconds is how stale an enrichment may get, not a per-tick setting. SOAP services often back slow-moving reference data, which tolerates a high TTL — but check that assumption rather than inherit the default.

Error handling

onError uses the same strategies as other filters:

ValueEffect
failStop the pipeline on the first SOAP error.
skipDrop the failing record.
logLog the SOAP error and keep the record, annotated under _errors.

With log, the record passes through carrying an error marker so you can route on the failure instead of losing it.

A SOAP fault is classified on its fault code, not on the HTTP status: SOAP 1.1 mandates 500 for every fault, so a Client / Sender fault is recorded as validation / not retryable, and a Server / Receiver fault as server / retryable. Any other fault code is recorded as non-retryable.

resultKey cannot be _errors — the key is reserved for the runtime's error markers and the pipeline fails validation.

Examples

examples/42-soap-call-enrichment.yamlview source ↗
42-soap-call-enrichment.yaml
name: soap-call-enrichment
version: 1.0.0
description: Poll orders every five minutes, enrich each record with a SOAP lookup, cache responses, and append the SOAP result under a result key.
tags:
  - soap
  - enrichment
input:
  type: httpPolling
  schedule: "*/5 * * * *"
  endpoint: https://source.example.com/api/orders
  dataField: orders
filters:
  - type: soap_call
    endpoint: https://soap.example.com/customers
    soapAction: urn:GetCustomer
    operation: GetCustomer
    body: |
      <m:GetCustomer xmlns:m="urn:customers">
        <m:CustomerId>{{record.customerId}}</m:CustomerId>
      </m:GetCustomer>
    dataField: Envelope.Body.GetCustomerResponse.Customer
    mergeStrategy: append
    resultKey: customer
    cache:
      enabled: true
      maxSize: 1000
      ttlSeconds: 300
      key: "{{record.customerId}}"
output:
  type: httpRequest
  endpoint: https://destination.example.com/api/orders/enriched
  method: POST
  requestMode: batch
  headers:
    Content-Type: application/json
examples/29-call-filters-shared-merge-contract.yamlview source ↗
29-call-filters-shared-merge-contract.yaml
name: call-filters-shared-merge-contract
version: 1.0.0
description: The three call filters share one merge contract - mergeStrategy append nests the whole response under resultKey.
tags:
  - http-call
  - soap-call
  - sql-call
  - append
input:
  type: httpPolling
  schedule: "*/15 * * * *"
  endpoint: https://source.example.com/api/orders
  dataField: orders
filters:
  - type: http_call
    endpoint: https://crm.example.com/api/customers
    method: GET
    keys:
      - field: customerId
        paramType: query
        paramName: id
    mergeStrategy: append
    resultKey: customer
    cache:
      enabled: true
      maxSize: 1000
      ttlSeconds: 300
      key: "customer:{{record.customerId}}"
  - type: soap_call
    endpoint: https://erp.example.com/contracts
    soapAction: urn:GetContract
    operation: GetContract
    body: |
      <m:GetContract xmlns:m="urn:contracts">
        <m:CustomerId>{{record.customerId}}</m:CustomerId>
      </m:GetContract>
    dataField: Envelope.Body.GetContractResponse.Contract
    mergeStrategy: append
    resultKey: contract
    cache:
      enabled: true
      maxSize: 1000
      ttlSeconds: 300
      key: "contract:{{record.customerId}}"
  - type: sql_call
    connectionStringRef: ${REFERENCE_DATABASE_URL}
    driver: postgres
    query: SELECT tier, discount FROM pricing WHERE customer_id = $1
    parameters:
      - record.customerId
    mergeStrategy: append
    resultKey: pricing
    cache:
      enabled: true
      maxSize: 1000
      ttlSeconds: 300
      key: "pricing:{{record.customerId}}"
output:
  type: httpRequest
  endpoint: https://destination.example.com/api/orders/enriched
  method: POST
  requestMode: batch
  headers:
    Content-Type: application/json

Cross-references