Using RPC with Fusion.js and Redux (Part 3)

Getting started

The application we will be working on was built in the previous article in this series. I would recommend you going through that article first. If you do not want to do that, you can clone that project from Github and then check out the basic-app tag.

What is RPC?

This was my question when I was reading the Fusion.js documentation. I had never heard of RPC in the context of web development.

RPC in web development is an alternative to RESTful architecture. Rather than defining your urls around nouns and request methods, the urls are defined as verbs. For example, you might have /api/books as an endpoint in a RESTful API. That single endpoint is used for both retrieving a list of, and creating, books. On the other hand, an RPC endpoint would look like /api/getBooks or /api/createBook.

Thanks to Fusion.js’ plugin architecture with its upstream/downstream nature, RPC in Fusion.js is quite interesting. As you will see, the plugin provides us with a helper function called withRPCRedux which we can compose into our component, providing us a function which fires off an API call using RPC. This is what happens:

  1. The client hits the API endpoint using the helper function. It calls the helper function passing in a request body, which should be a Javascript object. The reason it needs to be an object is so that it can be serialized on the client and sent over the wire to the server where it is deserialized and passed into the handler function.
  2. The “handler” function receives the deserialized request body.
  3. The handler function can do any processing it needs to, including hitting a database.
  4. The function needs to return a Javascript object which is received as serialized JSON by the client.
  5. The response will be dispatched as a Redux action. I will go into this in more detail later in this article.
  6. The proper reducer handles the action, updating the Redux state on the client side.

While this seems like a lot, it is not too bad once you have implemented it a few times. That is what we will be doing in this article.

Implementing fusion-plugin-rpc-redux-react

The first thing we need to do is view the readme file for the plugin by visiting https://github.com/fusionjs/fusion-plugin-rpc-redux-react. This file shows us how to install the plugin as well as how to interact with it.

If we compare the src/main.js file to the one in the “Setup” section of the readme, we find that the following lines need to be added to our file:

In addition to adding this configuration to our app, we need to install the plugins we are importing. The fusion-plugin-react-reduxplugin also depends on react-redux, which depends on redux, so we will install those as well. To do that, run yarn add fusion-plugin-universal-events fusion-plugin-react-redux fusion-plugin-rpc-redux-react fusion-tokens unfetch react-redux redux.

After installing the node modules, update the src/main.js file:

If you still have yarn dev running, you will notice that you now have an error saying that rpc/index.js and redux/index.js are missing. This is a perfect example of how awesome Fusion.js’ Hot Module Reloading (HMR) is!

The setup code we added included this:

What this does is register handlers to the RPCHandlersToken dependency injection token when it is run on the server side and registers the unfetch library to the FetchToken token on the client (browser) side. Any time these tokens are used in dependency injection, the registered values (libraries, functions, objects, etc) will be supplied for use.

As a side note, we are registering a FetchToken because the fusion-plugin-rpc-redux-react plugin automagically uses it on the browser side to hit the API endpoints for each RPC handler, while the handler function is called directly on the server during server side rendering.

The handlers value comes from importing rpc/index.js, so that is where we should put our RPC handlers. The file will export an object with key names that will be the names of our handler functions. These names are important, and will be used to reference the handler in other parts of our codebase. The value for each key needs to be an async function which returns an object that will be serialized and sent back to the client. This returned value will be received in our Redux actions as action.payload.

This is an example of a “no op” handler. It simply receives the request body, destructures value and sends it on to redux. If no server side processing needs to happen, this is a common way to handle it. As you can see, the handler also receives the context, which gives it access to the to HTTP request and response.

We will leave our handler in this state for now, and come back to it in a little while.

The other thing we registered is reducer to ReducerToken, so we need to take care of that next. Our redux/index.js file should export a standard Redux reducer. It can be built using compbineReducers, reduceReducers, or just a regular reducer function. There is nothing special about reducers in Fusion.js apps.

There is a special thing that happens as a result of using the RPC plugin though. When we start our RPC call, a Redux action of type <HANDLER_NAME>_START is fired. Next, our handler function is called. If an error is thrown in our handler function, it is caught and <HANDLER_NAME>_FAILURE is dispatched. If no error is thrown, <HANDLER_NAME>_SUCCESS is dispatched. You can see the source code responsible for that here.

To start with, we will write a traditional reducer function. Here are the reducer files:

Since we don’t want to make any changes when the action starts or fails, we simply return the current state. In a production app it would be a good idea to bring errors to the surface by adding them to the state in the failure clause so they can be displayed.

We could also leave the _START and _FAILURE clauses out since they are identical to the else clause, but I have included them for comparison against the next reducer we will create.

In case you don’t know about them, higher order components are components that return other components. We will be using withRPCRedux to compose a component which has access to our RPC action.

The change will be made in src/components/Input.js:

Quite a bit has changed here, so let’s go through it one item at a time.

First, we are importing compose from the redux library. If you are not familiar with it, I recommend reading the docs about it. Next, we import connect from react-redux, which is used to inject our Redux state into our component. The last new import is withRPCRedux, which is used to inject our RPC handler function into our component as a prop.

Our Input component has now been promoted from a direct export to a variable in order to use it in our HOC. Last, we have composed the connect and withRPCRedux function calls into a HOC function which accepts our Input component.

The next thing we need to do is update our component to use the new props we have provided to it:

It has been updated to destructure the value and increment props. Those props have been used to display the value as well as the in onClick handler to call the RPC action. You can see that we are passing an object to increment for serialization as I mentioned we would be doing.

You should now be able to refresh the browser (if it didn’t refresh itself, which it may have) and click the + button to see it increment the value!

We could have also incremented (or done any other work) on the server side. To see this, let’s update our handler and make our number change by a total of 10 by changing it on the server side in addition to the client side:

Head back to your browser and without even refreshing you will find that your value now increments by 10! This change was just an example and will not be in the rest of the code in this series.

First, we need to add a handler:

Next we will handle the Redux actions. This time, we will use createRPCReducer so we can compare it against our vanilla reducer. createRPCReducer is a function which is provided by fusion-plugin-rpc-redux-react. It needs to be called with an RPC action name, an object containing start, success, and failure reducer functions, and an optional initial state.

It has been added to the value.js file here:

There are a couple of things going on, but we will focus on the decrement object first. The increment and decrement reducers are doing exactly the same thing. The use of createRPCReducer is more concise, but there is nothing wrong with the verbose implementation if you prefer it.

The next thing you should notice is that we have added reduceReducers. This is a function from the reduce-reducers library (which you need to yarn add), that calls each of the function arguments in succession passing the return value of the last function into the next function. This allows us to have sibling reducers which work on the same piece of state.

Having sibling reducers work on the same piece of state was probably the thing I struggled with the most. It is amazing to see such a simple solution!

Once again, we need to update the Input.js file:

We have added the decrement prop as well as using used it in the onClick handler. We also composed it into our component once again using withRPCRedux.

That’s it for this part of the app. The only thing left to do is make our event log work, which we will tackle in the next article.

Anything which is register()ed in your app can either be the object or function that the dependency token needs, or a plugin that provides() it. That means our src/rpc/index.js file could also look like this:

In fact, you can update your file and you will see it still functions exactly the same.

To continue building the application, head to Connecting our event log.

Series links

An introduction to Fusion.js
Building a basic app in Fusion.js
Using RPC with Fusion.js and Redux (this article)
Connecting our event log
Comparing RPC reactors to RPC reducers in Fusion.js
Deploying your Fusion.js application to Heroku