Skip to content

Functional Composition

functional composition is a design pattern, that combines simple, reusable functions into a single pipeline to process data. This approach is highly readable and maintainable because each function has a single responsibility. We will be using a simple user registration details sanitization example to explain functional composition.

1. Reusable Utilities

This section defines a set of small, focused functions, each designed to perform a specific data transformation on an object.

Js

// Removes leading/trailing whitespace from string values
const trim = obj => Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k, typeof v === "string" ? v.trim() : v])
);

// Converts all object keys to lowercase
const toLowerKeys = obj => Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);

// Filters out entries with empty strings or null values
const removeEmpty = obj => Object.fromEntries(
  Object.entries(obj).filter(([_ , v]) => v !== "" && v != null)
);

// Returns a function that keeps only specified keys
const whitelist = allowed => obj =>
  Object.fromEntries(Object.entries(obj).filter(([k]) => allowed.includes(k)));

2. The Function Composer

The compose function is the core of the pattern. It's a higher-order function that takes multiple functions and returns a new function. This new function executes the input functions in a right-to-left order, passing the output of one function as the input to the next.

js
// Creates a pipeline of functions that run from right to left
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);

3. The Sanitization Pipeline

Here, the compose function is used to build a complete data sanitization pipeline called sanitizeRegistration. This creates a single, easy-to-use function that performs multiple transformations in a specific order.

js
const sanitizeRegistration = compose(
  whitelist(["email", "username", "age"]), // Only keeps these keys
  removeEmpty,                              // Removes empty fields
  toLowerKeys,                              // Normalizes keys to lowercase
  trim                                      // Trims whitespace from values
);

4. Usage

This part demonstrates how the sanitizeRegistration pipeline is used to process a raw input object. The result is a clean, standardized object that has been transformed by all the functions in the pipeline. The Password and Bio fields are removed, and the Email and Username keys are converted to lowercase with their values trimmed.

js
const rawInput = {
  Email: " koome@devsip.tech ",
  Username: " devGuy ",
  Age: "25",
  Password: "secret",
  Bio: ""
};

// The rawInput object is passed through the entire sanitization pipeline.
console.log(sanitizeRegistration(rawInput));

javascript book

If this interested you, check out my Javascript Book

Enjoy every byte.