Validators
Validate incoming messages before transformation
Overview
Validators are TypeScript functions that run before the transformer in a channel's
processing pipeline. They inspect the structure and content of incoming messages and either accept
them silently (by returning void) or reject them (by throwing an Error).
When a validator throws, the message is immediately rejected — it never reaches the transformer or any destination. If error handling is configured for the channel (e.g. a dead-letter queue), the rejected message and the error details are forwarded there for later inspection.
Configuration
Validators are declared in a channel's channel.yaml. There are two equivalent ways
to wire a validator into the pipeline.
Explicit validator block
validator:
runtime: node
entrypoint: validator.ts
Pipeline shorthand
pipeline:
validator: validator.ts
Writing a Validator
A validator is a named export called validate. It receives the parsed message and
an optional context object. If the function returns normally, the message is accepted. If the
function throws an Error, the message is rejected.
Function signature
export function validate(msg: unknown, ctx?: { channelId: string; correlationId: string }): void {
// Throw an error to reject the message
// Return void to accept
}
| Parameter | Type | Description |
|---|---|---|
msg |
unknown |
The incoming message, automatically parsed according to data_types.inbound |
ctx.channelId |
string |
The name of the channel processing this message |
ctx.correlationId |
string |
Unique correlation ID for distributed tracing |
Examples
Basic Object Validation
Reject anything that is not a non-null object:
export function validate(msg: unknown): void {
if (!msg || typeof msg !== "object") {
throw new Error("Message must be a non-null object");
}
}
HL7 ADT Message Validation
Ensure required segments and fields are present on an HL7v2 ADT message:
export function validate(msg: unknown): void {
const m = msg as Record<string, any>;
if (!m.MSH) throw new Error("Missing MSH segment");
if (!m.PID) throw new Error("Missing PID segment");
if (!m.PID["3.1"]) throw new Error("Missing patient ID (PID-3.1)");
if (!m.EVN) throw new Error("Missing EVN segment");
}
FHIR Resource Validation
Validate that a FHIR resource has the required type and mandatory fields:
export function validate(msg: unknown): void {
const resource = msg as Record<string, any>;
if (!resource.resourceType) {
throw new Error("Missing resourceType");
}
if (resource.resourceType === "Patient") {
if (!resource.identifier?.length) {
throw new Error("Patient must have at least one identifier");
}
if (!resource.name?.length) {
throw new Error("Patient must have at least one name");
}
}
}
Lab Result Validation
Check that a lab result message has all the required fields and a well-formed results array:
export function validate(msg: unknown): void {
const lab = msg as Record<string, any>;
if (!lab.orderId) throw new Error("Missing orderId");
if (!lab.patientId) throw new Error("Missing patientId");
if (!lab.results || !Array.isArray(lab.results)) {
throw new Error("results must be an array");
}
for (const result of lab.results) {
if (!result.code) throw new Error("Each result must have a code");
if (result.value === undefined) throw new Error("Each result must have a value");
}
}
Error Handling
When a validator throws an Error, intu handles the rejection as follows:
- The message is rejected and does not proceed to the transformer or any destination.
- The error is logged with the original message payload and the thrown error message.
- If
error_handling.dlqis configured in the channel's YAML, the message is forwarded to the dead-letter queue along with error metadata. - The
messageproperty of the thrownErroris included in the error log entry, so use descriptive messages to make debugging easier.
error_handling:
dlq:
ref: kafka-dlq
include_original: true
include_error: true
"Missing patient ID (PID-3.1)" are far easier to triage than generic
"Validation failed" strings.
Data Types
When data_types.inbound is set in channel.yaml, intu automatically
parses the raw incoming payload before it reaches the validator. The
msg argument your validator receives is already the parsed representation.
| Data Type | Parsed As |
|---|---|
raw |
Raw string — no parsing applied |
json |
Parsed JSON object |
xml |
Parsed XML represented as a JSON structure |
csv |
Parsed CSV as an array of objects (header row becomes keys) |
hl7v2 |
Parsed HL7v2 message as a JSON structure with segment/field accessors |
fhir_r4 |
Parsed FHIR R4 resource (JSON) |
x12 |
Parsed X12 transaction as a JSON structure |
data_types:
inbound: hl7v2
outbound: fhir_r4
data_types.inbound is not set, the message is passed to the validator
as a raw string. Your validator is then responsible for any parsing it needs.