Through the magic of refactoring, I will turn a pair of Express route handlers into a Redux reducer function using only…bananas (disclaimer: this post has little to do with bananas, and everything to do with state and functional code). Observe. Take these two express handlers which interact with an imaginary database:

RESTful Bananas

What are the defining features of this code? Is it functional? Yes it is. Is it stateless? Yes, and sort of. There is shared state in the form of the database. But without some shared state that can be changed or recreated your app would be pretty boring. The code itself though is functional, and we trust the database to manage the shared state. So the code is functional and stateless, but it looks nothing like a reducer. What if instead of using the app.post and app.put methods, we use app.use to handle both types of requests?

Now it looks a bit more like a Redux reducer function. Requests in a REST API are processed much like actions in the Redux reducer: conditionally and in isolation. I say the Redux reducer instead of a Redux reducer, because much like an Express app it’s really one function composed of smaller functions with some conditional statements to determine which statements are executed in response to an action / request.

In the case of Express, the request has a URL and a method. The URL is being used to invoke a particular handler that deals with a particular part of the application state. The method is used finally to determine how we’d like to affect that state. With Redux all the reducers are invoked for every action, but there’s an action type which allows for conditionally running code. In both cases actions and requests are processed by their lonesome, with the shared state that they affect being stored in a single place.

What about that shared state though? How is a database like the Redux store? Well what if we modified things a bit. This is an imaginary database, so we can create our own api as we see fit. Let’s say that we’ve wrapped our handler such that we fetch the entire collection of bananas and pass it as the first argument. We then modify it and set it into the database using a synchronous method in the database api called setBananas. We’ll also make this method just handle data, and assume that we send the response in another function.

This isn’t so different than the previous example, and even closer to a reducer function. Instead of calling db.insert and db.updateById, all of the banana state is being passed as an argument to our function, and we’re doing the insert and update ourselves directly. If we imagine that the database isn’t a separate server, but just another part of our application, then it doesn’t matter so much where we do the actual update. So we do the specifics of updating the data here, and generically set the new data into the database with setBananas.

This isn’t so different from how the reducer works in Redux. We get the current state as an argument, we create new state, and set it into the store by returning it. Not so different right? In the above example we’re modifying the array and objects directly, so let’s do one more change to create new arrays and objects, and then look at the Redux reducer which performs a similar job:

Pretty similar right? So why does this analogy work? It works because Express code for REST API’s and our Redux code is basically functional, and stateless. We process data which represents the artifact of some event, like a request to the server or some user or server event on the client. The side effects that result from that processing, the changes in the state of our application, all happen in one place: the database / store. Because we have trusted code managing side effects, we can focus on writing clean functional applications. Now, how do you like them bananas?