Skip to content

Convert and property processors

pkg/processor/convert.go defines small, focused processors for type coercion and exchange-property manipulation:

  • ConvertBody — coerce the message body to a target Go type (Message Translator EIP)
  • SetProperty / RemoveProperty / RemoveProperties — exchange-property writes (mirroring the header processors in transform)
  • SetExchangePattern — switch between InOnly and InOut
  • ThrowException — fail the exchange with a typed error
  • TargetDynamic — endpoint URI computed at runtime
  • ScriptProcessor — compatibility wrapper around a transform processor

Processors in this file

NewConvertBody

Coerces the body to a supported Go type. Implements the simple-form Message Translator EIP for type changes that don't need an expression.

steps:
  - convert-body:
      type: int
Field Type Default Description
type string required Target type. One of string, []byte, int, float64, bool, json (alias map).
charset string accepted but unused Reserved for future encoded-string conversions.

Constructor: NewConvertBody(targetType, charset string) *ConvertBody.

Conversion table:

Target From int/int64/float64 From string From []byte From map/other
string fmt.Sprintf("%v", v) as-is as-is via %v fmt.Sprintf("%v", v)
[]byte []byte(fmt.Sprintf(...)) []byte(s) as-is byte cast of %v
int direct/truncate strconv.Atoi error error
float64 promote strconv.ParseFloat error error
bool v != 0 strconv.ParseBool error error
json / map json round-trip json.Unmarshal json.Unmarshal json round-trip

A nil body is a no-op (returns nil with no conversion).

NewSetProperty / NewSetPropertyConstant

Sets a named property on the exchange. Properties differ from headers in that they live on the exchange envelope, not the message — they survive ex.Copy() but don't travel with serialized bodies.

steps:
  - set-property:
      name: HelixTenantId
      starlang: header("X-Tenant")
      # or:
      constant: "acme"
Field Type Default Description
name string required Property key. Helix uses the Helix* prefix for built-in metadata.
starlang string one of Starlang expression evaluated per exchange.
constant string one of Static string value.

Constructors:

  • NewSetProperty(name string, value func(ctx, ex) any) *SetProperty — dynamic property.
  • NewSetPropertyConstant(name, constant string) *SetProperty — constant value.

NewRemoveProperty

Removes a single property by exact name.

steps:
  - remove-property: HelixTenantId

Constructor: NewRemoveProperty(name string) *RemoveProperty.

NewRemoveProperties

Removes all properties whose key matches a glob pattern, with an optional except whitelist. Equivalent to RemoveHeaders but for properties.

steps:
  - remove-properties:
      pattern: "Helix*"
      except: ["HelixWorkflowId"]
Field Type Default Description
pattern string required Go filepath.Match glob pattern.
except list empty Property names to preserve.

Constructor: NewRemoveProperties(pattern string, except ...string) *RemoveProperties.

NewSetExchangePattern

Switches the exchange's message exchange pattern (MEP) between InOnly (fire-and-forget) and InOut (request-reply).

steps:
  - set-exchange-pattern: InOut
Field Type Default Description
(string body) string required InOnly or InOut. Anything else falls back to InOnly.

Constructor: NewSetExchangePattern(pattern exchange.ExchangePattern) *SetExchangePattern.

NewThrowException

Aborts processing with a typed error. The error message is prefixed with the type (if set) so downstream do-try matchers can ErrorContains(type).

steps:
  - throw-exception:
      message: "missing required field"
      type: "ValidationError"
Field Type Default Description
message string required Error message.
type string optional Logical error type. Prepended to the message as <type>: <message>.

Constructor: NewThrowException(message, errType string) *ThrowException.

NewTargetDynamic

Sends the exchange to a URI computed at runtime from an expression.

steps:
  - target-dynamic:
      starlang: '"kafka://" ++ header("X-Topic")'
Field Type Default Description
starlang string required Expression returning a non-empty URI. Empty results return an error.

Constructor: NewTargetDynamic(uriFunc func(ctx, ex) string, resolver EndpointResolver) *TargetDynamic. Resolves the URI through the same EndpointResolver used by RecipientList and RoutingSlip.

NewScript

Compatibility shim: wraps a transform processor and exposes it under the script step name. The processor delegates straight through to the inner one — there is no language switch. Use when porting routes that rely on the script step name.

Constructor: NewScript(processor engine.Processor) *ScriptProcessor.

Examples

workflows:
  - id: tenant-routing
    trigger: { uri: http://localhost:8080/in }
    steps:
      - set-property:
          name: HelixTenantId
          starlang: header("X-Tenant")
      - convert-body: { type: json }
      - target-dynamic:
          starlang: '"kafka://tenant-" ++ property("HelixTenantId")'
      - remove-properties:
          pattern: "Helix*"
          except: ["HelixWorkflowId"]

Source

pkg/processor/convert.go

See also

  • transform — header writes and body expression rewrites.
  • remove_headers — header equivalent of remove-properties.
  • routing — RecipientList, RoutingSlip, DynamicRouter for the URI-driven routing patterns.
  • error_handling — do-try catches ThrowException errors.