Nornir is a TypeScript lib that provides a strongly typed middleware chain for event processing in Node.js with a fluent API. It allows developers to create a chain of middleware functions that execute one after the other, passing a result from one function to the next.
You can install Nornir using NPM or Yarn:
npm install @nornir/core
yarn add @nornir/core
import nornir from "@nornir/core";
import type { ALBEvent, ALBHandler } from "aws-lambda";
interface Event1 {
type: "Event1";
data: string;
}
interface Event2 {
type: "Event2";
thing: number;
stuff: {
other: boolean;
test: true;
};
}
type Event = Event1 | Event2;
export const handler: ALBHandler = nornir<ALBEvent>()
.use(input => [{ type: "Event1", data: input.body } as Event])
.split(
chain =>
chain
.use(input => ({ cool: input.type, event: input }))
.use(input => input.event),
)
.use(input => input[0].unwrap())
.match("type", {
Event1: chain => chain.use(input => input.data),
Event2: chain => chain,
})
.use(input => {
return {
statusCode: 200,
body: JSON.stringify(input),
};
})
.build();
All methods
Adds a middleware function to the chain. The middleware function takes the output of the previous step as an input and returns a new output. The function can be either synchronous or asynchronous.
nornir.use((input: MyStepInputType, registry: AttachmentRegistry) => {
// Do something with the input
return input.thing;
});
Adds a middleware function to the chain. Identitical to use, but the input is wrapped in a Result object that allows you to unwrap the value or handle errors.
nornir.useResult(
async (input: Result<MyStepInputType>, registry: AttachmentRegistry) => {
// Unwrap the input and do something with it
return input.unwrap();
},
);
Adds a Nornir chain to the current chain. Allows developers to compose multiple Nornir chains.
const subChain = new Nornir<MySubChainInputType>()
.use((input, registry) => {
// Do something with the input
return mySubChainOutput;
});
nornir.useChain(subChain);
split(builder: (chain: Nornir) => Nornir<Item, ItemResult>, concurrency: number): Nornir<Input, Output>
Splits an array of inputs and processes them through a chain with configurable concurrency. Returns an array of result objects. Execution will not stop if an item fails, they can all resolve or reject individually.
nornir.split(chain =>
chain.use(item => item.property++)
.use(item => ({ test: item }))
).use(outputs => outputs.map(output => output.unwrap()));
Pattern match on a property of a discriminated union. Branch is chosen based on the value of the property. Matching is exhaustive, so all possible values of the property must be handled.
interface Event1 {
type: "Event1";
data: string;
}
interface Event2 {
type: "Event2";
thing: number;
stuff: {
other: boolean;
test: true;
};
}
type Event = Event1 | Event2;
export const handler = nornir<Event>()
.match("type", {
Event1: chain => chain.use(input => input.data),
Event2: chain => chain,
});