Skip to main content

routes — Route Messages

"Routing" is the term used for outbound processing of messages in Gofer Engine. You can develop channel routes in either the JSON config route following the Route type, or you can use the OOP style and follow the ORoute interface.

Using JSON Style

Alternatively use OOP style.

Using object configs offer simplified strongly typed configuration and allows the configs to be easily stringified to JSON and broken apart for exporting/importing.

The routes property in the ChannelConfig type takes a multidimensional arrays of Routes. This allows routes to be procecessed syncronously or asyncronously. Routes within the same inner array will be called sequentially, If a route sends to a tcp server, then the next route will be using the ACK returned by that server.

configRouteExample.ts
import gofer, { ChannelConfig, Route, RouteFlow } from '@gofer-engine/engine';

const sendMsg: RouteFlow = {
kind: 'tcp',
tcp: {
host: 'localhost',
port: 5600,
msgType: 'HL7v2',
}
};

const storeAck: RouteFlow = {
kind: 'store',
file: {},
};

const route: Route = {
kind: 'route',
id: "ID_1",
name: "Example Config Route 1",
tags: [{ name: "Examples" }],
flows: [sendMsg, storeAck],
};

const channel: ChannelConfig = {
name: 'Example Channel Config',
source: {
kind: 'schedule',
schedule: {
msgType: 'HL7v2',
schedule: '0 /15 * * * *',
runner: {
kind: 'file',
file: {
directory: '/tmp',
filterOptions: {
filenameRegex: '.*\\.hl7',
}
},
}
},
},
ingestion: [
{
kind: 'ack',
ack: {
organization: 'Example Org',
}
},
],
routes: [route],
};

gofer.configs([channel]);

Using OOP Style

Alternatively use JSON style.

name

Call the name method to name the route

oopRoutingExample.ts
    .name('A Unique Route Name')

id

Call the id method to override the generated id given to the route. If not provided the id will be a UUID

oopRoutingExample.ts
    .id(42)

filter

Call the filter method to filter the message. See Filter Flow for the function definition

oopRoutingExample.ts
    .filter((msg) => msg.get('MSH-9.1') === 'ORM')

transform

Call the transform method to transform/modify the message. See Transform Flow for the function definition

oopRoutingExample.ts
    .transform((msg) => msg.set('MSH-5', 'Gofer Engine'))

store

Call the store method to persist the message to a data store. See Store Config for the config definition

oopRoutingExample.ts
    .store({ file: {} })

setVar

Call the setVar method to set a variable value for the specific scope. The varValue can either be the value itself or a function to callback to retrieve the value from the message and context. See Variables for more information on using variables.

oopRoutingExample.ts
    .setVar('Msg', 'name', 'John Doe')
.setVar('Channel', 'facility', (msg) => msg.get('MSH-3.1'))
.setVar<{ bar: string }>('Global', 'foo', { bar: 'baz' })

setMsgVar

Call the setMsgVar method to set a variable value for the Message scope. Later in this message will be able to use this variable. The varValue can either be the value itself or a function to callback to retrieve the value from the message and context. See Variables for more information on using variables.

oopRoutingExample.ts
    .setMsgVar('name', 'John Doe')

setRouteVar

Call the setMsgVar method to set a variable value for the Message scope. Later in this message will be able to use this variable. The varValue can either be the value itself or a function to callback to retrieve the value from the message and context. See Variables for more information on using variables.

oopRoutingExample.ts
    .setRouteVar<number>('port', 5808)

setChannelVar

Call the setChannelVar method to set a variable value for the Channel scope. Later in this message or following messages within this same channel will be able to use this variable. The varValue can either be the value itself or a function to callback to retrieve the value from the message and context. See Variables for more information on using variables.

oopRoutingExample.ts
    .setChannelVar('facility', (msg) => msg.get('MSH-3.1'))

setGlobalVar

Call the setGlobalVar method to set a variable value for the Global scope. Anywhere later in current or following messages within this same server will be able to use this variable. The varValue can either be the value itself or a function to callback to retrieve the value from the message and context. See Variables for more information on using variables.

oopRoutingExample.ts
    .setGlobalVar<{ bar: string }>('foo', { bar: 'baz' })

getVar

Call the getVar method to get a previously set variable for the given scope by name. Define the callback function (cb) to do something with the value of the variable. You can use the value to filter or transform the message, or do something with the MessageContext.

To filter the message, return a boolean.

To transform the message, return the transformed Msg class instance You can return undefined or even not return anything (void)

oopRoutingExample.ts
    .getVar('Msg', 'name', (name) => console.log(name))

getMsgVar

Call the getMsgVar method to get a previously set variable for the Msg scope.

oopRoutingExample.ts
    .getMsgVar('name', (name, msg) => msg.set('PID-5.2', name))

getRouteVar

Call the getRouteVar method to get a previously set variable for the Route scope.

oopRoutingExample.ts
    .getRouteVar('port', (port, _msg, context) =>
context.logger(`Using port ${port}`, 'debug'),
)

getChannelVar

Call the getChannelVar method to get a previously set variable for the Channel scope.

oopRoutingExample.ts
    .getChannelVar<string>('facility', (facility, _, { logger }) => {
logger(`Received message from ${facility}`, 'info');
})

getGlobalVar

Call the getGlobalVar method to get a previously set variable for the Channel scope

oopRoutingExample.ts
    .getGlobalVar<{ bar: string }>('foo', ({ bar }, msg) =>
msg.set('NTE-2', bar),
)

send

Call the send method to configure a destination to send the message.

For example, you can send the message via TCP to the IP and port provided by your EHR

oopRoutingExample.ts
    .send('tcp', 'ehr.example.com', 5700)

You can also use a function to extract this information from the message, the context, or variables.

oopRoutingExample.ts
    .send(
'tcp',
(_msg, { getChannelVar }) =>
`${getChannelVar<string>('facility')}.example.com`,
(_msg, context) => context.getRouteVar<number>('port'),
),

Another example, you can send the message to an HTTPS endpoint with a self-signed certificate, and provide basic authorization.

oopRoutingExample.ts
    .send('https', {
host: 'ehr.example.com',
port: 443,
basicAuth: {
username: 'user',
password: 'pass',
},
rejectUnauthorized: false,
})

export

Call the export method to save the configuration to a JSON object. This method is mainly used for testing purposes and inner implementation.

Simplified types

type Route = {
kind: 'route';
id?: string | number;
name?: string;
tags?: Tag[];
queue?: QueueConfig;
flows:
| SetRequired<RouteFlowNamed, 'id'>[]
| (RouteFlow | RouteFlowNamed)[];
}

type RouteFlow =
| FilterFlow
| TransformFlow
| TransformOrFilterFlow
| ({ kind: "store" } & StoreConfig)
| Connection;

type Connection =
| { kind: "tcp"; tcp: TcpConfig }
| { kind: "http"; http: HTTPConfig }
| { kind: "https"; https: HTTPSConfig };

type RouteFlowNamed = {
kind: "flow";
id?: string | number; // a unique id for this route flow. If not provided will use UUID to generate. if not defined it may not be the same between deployments/reboots
name?: string; // a human readable name for this route flow. Preferrably unique
tags?: Tag[]; // Tags to help organize/identify route flows
queue?: QueueConfig;
flow: RouteFlow;
};

interface ORoute {
name: (name: string) => ORoute;
id: (id: string | number) => ORoute;
filter: (f: FilterFunc) => ORoute;
transform: (t: TransformFunc) => ORoute;
store: (s: StoreConfig) => ORoute;
setVar: <V>(scope: varTypes, varName: string, varValue: MsgVar<V>) => ORoute;
setMsgVar: <V>(varName: string, varValue: MsgVar<V>) => ORoute;
setRouteVar: <V>(varname: string, varValue: MsgVar<V>) => ORoute;
setChannelVar: <V>(varName: string, varValue: MsgVar<V>) => ORoute;
setGlobalVar: <V>(varName: string, varValue: MsgVar<V>) => ORoute;
getVar: <V>(scope: varTypes, varName: string, getVal: WithVarDo<V>) => ORoute;
getMsgVar: <V>(varName: string, getVal: WithValDo<V>) => ORoute;
getRouteVar: <V>(varName: string, getVal: WithValDo<V>) => ORoute;
getChannelVar: <V>(varName: string, getVal: WithValDo<V>) => ORoute;
getGlobalVar: <V>(varName: string, getVal: WithValDo<V>) => ORoute;
send(method: 'tcp', host: string, port: number): ORoute;
send(method: 'http', options: IHTTPConfig): ORoute;
send(method: 'https', options: IHTTPSConfig): ORoute;
export: () => SetRequired<Route, "id" | "flows">;
}

Advanced Config Style Conformance

For advanced type control, you can pass through generics to the Route, RouteFlow, and RouteFlowNamed typed.

  1. The first generic seen in source as Filt controls the type of the filter style to either (F) Functional configs, (O) Ojectified configs, or (B) to allow Both config styles.
  2. The second generic seen in source as Tran controls the type of the transformer style to either (F) Functional configs, (O) Ojectified configs, or (B) to allow Both config styles.
  3. The third generic seen in source as Stct controls controls the strictness of the configs to either (S) Strictly require objectified configs with ids, or (L) then allow looser config without requirind ids.