Forever Functional: Chaining Calls for Fluent Interfaces
Tags: javascript, functional, tutorial
Published: 2021-06-25 06:28:47

_by author [Federico Kereki](https://blog.openreplay.com/authors/federico-kereki)_

Chaining calls is a way to design fluent interfaces, which in turn allow for clearer, more understandable code.

How do you design a clear API? More specifically, how can you make your API easier to use? The concept of a "fluent interface", based on "chaining", lets you provide a more streamlined development experience to developers. While in the two previous articles in this series ([here](https://blog.openreplay.com/forever-functional-memoizing-functions-for-performance) and [here](https://blog.openreplay.com/forever-functional-memoizing-promises)) we looked at improving performance, now we'll focus on improving clarity and usability.

## What is Chaining?

Composing and pipelining are common patterns to apply a sequence of transformations when you work functionally . However, when you work with arrays or objects, there's another way of linking those calls: by *chaining* them. A well known example of this is provided by `map(...)` or `filter(...)`, each of which returns a new array, to which you can apply further calls. As a trivial (somewhat exaggerated!) example, let's see some code from my [Mastering JavaScript Functional Programming](https://www.packtpub.com/product/mastering-javascript-functional-programming-second-edition/9781839213069) book. We can start by defining some essentially nonsensical operations:

```javascript
const testOdd = x => x % 2 === 1;
const testUnderFifty = x => x < 50;
const duplicate = x => x + x;
const addThree = x => x + 3;
```

We can now apply those maps and filters, in sequence, to an array:

* First, we'll drop even numbers;
* then, we'll duplicate those that are left;
* we'll filter out results that are 50 or more;
* and we'll finish by adding 3 to whatever remains.

```javascript
const myArray = [22, 9, 60, 24, 11, 63];

const a0 = myArray
  .filter(testOdd)
  .map(duplicate)
  .filter(testUnderFifty)
  .map(addThree);
// [ 21, 25 ]
```

The `.map(...)` and `.filter(...)` operations return a new array, to which you can apply further operations. You could have done this in several lines as shown below, but (I hope) you'll agree that this isn't as clear. (A reader would wonder if `x1`, `x2`, and `x3` would be used again, for example.) This is the alternative code:

```javascript
const x1 = myArray.filter(testOdd);
const x2 = x1.map(duplicate);
const x3 = x2.filter(testUnderFifty);
const a0 = x3.map(addThree);
// [ 21, 25 ]
```

So, chaining implies that operations will return some object to which you may apply further operations. This is interesting by itself, but it makes more sense in the context of "Fluent Interfaces", which we'll discuss below.


## What are Fluent Interfaces?

What is a "fluent interface"? The term was invented by Martin Fowler [back in 2005](https://martinfowler.com/bliki/FluentInterface.html); the idea is chaining method calls, so code will be more legible, almost becoming a domain-specific language. A fluent API is primarily designed to be highly readable, using terms (methods) that are close to the domain you're working on. This explanation may be hard to understand, I admit, so let's see a couple of examples.

A well-known library that implements a fluent interface is [jQuery](https://jquery.com/). For example, you can write something like the following, that will access a DOM element, set some of its attributes, add CSS, and make the element visible, all in a single line.

```
$("#titlephoto")
  .attr({
    alt: "Street scene",
    title: "Pune, India",
  })
  .css("background-color", "black")
  .show();
```

You could get the same result in several lines -- but this is cleaner. Another example: the testing framework [Jest](https://jestjs.io/) applies fluent interfaces everywhere. For example, you can define a mock function that will return true once, then false, and undefined from that point on, in a single line.

```
const fakeTest = jest
  .fn()
  .mockReturnValueOnce(true)
  .mockReturnValueOnce(false)
  .mockReturnValue(undefined);
```

Let's go for a final example. The popular [D3.js](https://d3js.org/) library also uses this style to join together several method calls.

```
d3.select("svg")
  .append("text")
  .attr("font-size", "20px")
  .attr("transform", "translate(100,0)")
  .attr("x", 150)
  .attr("y", 200)
  .text("Sample Chart Title");
```


The key to the concept of a fluent interface is that it somehow mimics the way you think ("ok, select such element, append some text to it, change its font size, ...") making code more understandable. Chaining method calls is the way to achieve this, but don't just think of it as a way to allow to write shorter code or avoid needing some extra intermediate variables. Conciseness and terseness are convenient, but not necessarily the best reasons for adopting the chaining pattern. Instead, consider chaining as a means to develop a Fluent Interface.

With this out of the way, let's consider how we can implement this pattern by ourselves, for our own code.

## DIY: Chaining method calls

How can we implement chainable methods? The first solution, doing it by hand, is possibly the simplest. We just have to modify each method to `return this` at the end -- excepting, obviously, methods that need to return something else! This is certainly a solution, but we may think of something that needs less work, and *proxy* objects are a possibility.

A [proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) can intercept calls to another object, redefining how it works. You define a proxy by providing an object (the one whose methods will be intercepted) and a handler, that will implement whichever changes you want to achieve. Note that we won't be able to "proxify" a class; we have to proxify each object by itself.

In our case, we'll want to intercept all method calls, and make them return a reference to the object itself... unless, of course, the method is returning something else. This poses a slight problem: how do we detect if a method isn't returning anything. JavaScript, by default, works as if a `return undefined` statement had been added to functions or methods that don't otherwise return anything - so if your class has a method that may actually return `undefined`, we're in trouble!

An implementation of this proxy may be as follows; the `makeChainable(...)` function will transform an object into a chainable alternative, all of whose methods (that don't return `undefined`) will be returning a reference to the object itself.

```javascript
const makeChainable = (obj) =>
  new Proxy(obj, {
    get(target, property, receiver) {                        /* 1 */
      return typeof target[property] === "function"          /* 2 */
        ? (...args) => {                                     /* 3 */ 
            const result = target[property](...args);        /* 4 */
            return result === undefined ? receiver : result; /* 5 */
          }
        : target[property];                                  /* 6 */
    }
  });
```

A handler provides multiple "traps" for different operations and types of access. We want to intercept "get" calls (1) that make target methods or attributes. If the target is a function (2) we'll return a modified function that will accept the same arguments (3) as the original method, invoke that method (4), and then test if the result was undefined in which case it will return a reference to the proxied object (5) instead of the original returned value. If the target wasn't a function, it was an access to an attribute; we return it (6).

## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue. 
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).

## A gangland example

Let's say we are developing an application with data on mobsters from the thirties -- maybe we're setting up a new "Untouchables" movie? We could have a class allowing us to record the first and last names of a criminal, as well as its nickname or alias.

```javascript
class Mobster {
  constructor(firstName, lastName, nickname) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.nickname = nickname;
  }

  setFirstName(newFirst) {
    this.firstName = newFirst;
  }
  
  setLastName(newLast) {
    this.lastName = newLast;
  }
  
  setNickname(newNickname) {
    this.nickname = newNickname;
  }
  
  getFullName() {
    return `${this.firstName} "${this.nickname}" ${this.lastName}`;
  }
}
```

As is, objects in this class aren't chainable. The three setters do not `return this`, so you cannot chain methods. Certainly, we could rewrite the class by adding some lines as follows... but we'll look for a better, functional way of doing this.

```javascript
class Mobster {
  constructor(...) { ... }

  setFirstName(newFirst) {
    this.firstName = newFirst;
    return this;                 /* added */
  }
  
  setLastName(newLast) {
    this.lastName = newLast;
    return this;                 /* added */
  }
  
  setNickname(newNickname) {
    this.nickname = newNickname;
    return this;                 /* added */
  }
  
  getFullName() { ... }
}
```

To simplify creating new chainable objects, we could write a helper or we'll first have to create an object and then make it chainable; it's better to do all this in a single step. The helper we need does those two steps at once.

```javascript 
const makeMobster = (...args) => makeChainable(new Mobster(...args));
```

Now we can write code as follows.

```javascript
const gangster = makeMobster("Alphonse", "Capone", "Al");
console.log(gangster.getFullName());
// Alphonse "Al" Capone

console.log(
  gangster
    .setFirstName("Benjamin")
    .setLastName("Siegel")
    .setNickname("Bugsy")
    .getFullName()
);
// Benjamin "Bugsy" Siegel
```

Using chaining, you can design your code to be fluent, for more readable code -- by changing how you create an object!

## Summary

When designing an API of your own, going for a fluent interface produces a more easily used library. Chaining is key in implementing this pattern, and functional programming lets you transform any object into a chainable equivalent, instead of having to do it by hand. With this technique, your code will become simpler and more understandable; try it out!