Bringing it All Together

Let’s combine the code written in this chapter’s previous lessons.

We'll cover the following...

Summing up

Let’s try to bring our entire program together for the first time. We want our handler to look like this:

Press + to interact
// some imports
export const handler = async () => {
return pipe(
generateConfig(),
T.fromIO,
T.chain(checkLambda),
T.map(httpResultFromStats),
)();
};

To make inference and usage of fp-ts simple, we again resort to using a pipe. Inside that pipe, we generate the configuration and get back an IO. But our other actions are all asynchronous and therefore Tasks! So, how do we deal with this mismatch? One way to do it is to lift our IO stuff to Task. For that, we can use one of the built-in Task functions, fromIO. From that point on, we’re working with a Task, which is why we use its chain to pass our config to an as-yet-unwritten checkLambda function.

Note: We could also have used tagless final to abstract away the concrete monads we’re using, but that’s a more advanced technique we’ll briefly discuss later on.

This function runs our metric retrieval and transformations for the Lambda, which is passed in through config. It therefore takes in a config and returns ReducedStats, which then maps to an HTTP result using a function we wrote earlier. Let’s fill in the implementation:

Press + to interact
const checkLambda = (config: Config) => {
return pipe(
retrieveMetrics(config.between, METRICS)(config.functionName),
TE.map(statsResultToStatsSumResult),
TE.map(statsReducer),
TE.fold(
(message) => T.task.of(reducedStatsForFailure(message)),
T.task.of),
);
}

We’re combining the functions we wrote in the previous pages. We pass our metrics, time, and function name to our retrieveMetrics call. Next, we transform those results twice, using map and two of the pure transformers we defined earlier. Unfortunately, our call could fail because we’re dealing ...