Middleware in Redux architecture for android application
In the previous article, I wrote about Redux architecture and how it can be used in an android app - Redux architecture for android apps. At the end of the article, I briefly talked about Middleware
. I found Middleware to be the most confusing part about the Redux architecture and none of the posts about Redux architecture talk about much about it so it’s quite difficult to wrap your mind around it.
What is Middleware?
Middleware is a software or piece of code that acts as a bridge between between two different software or two different pieces of code. eg. A middleware could be a bridge between operating system and the database. Or in our case, a middleware could be a bridge between our Redux store and our db, network api calls.
This definition still seems very vague. From the redux website, A middleware provides an extension point between dispatching an action, and the moment it reaches the reducer. In Redux, middlewares are used for logging, crash reporting, connecting to an API, routing and other stuff.
How does middleware work in Redux?
From my understanding, a middleware or a list of middleware, changes the action that is dispatched to the store, before it reaches the reducers. Have a look at the flow diagram that I have made.
What happens inside the store with the middleware?
The above diagram is a bit simplified. The simplified version is - The dispatched action is sent to the middleware. The middleware acts on the input and decides if it wants to change the action. It then calls the second middleware in the chain with the updated action and so on. The last middleware then dispatches the action to the store.
Let’s look at an example of how an API middleware will work. According to the docs, a middleware takes AppState and Action as input and returns Action (same or new).
This is the simplest form of Middleware. Action A1 is dispatched. Middleware M1 changes the action A1 to A2. Middleware M2 does nothing and returns A2. Middleware M3 changes the action A2 to A3. The store calls the reducers to reduce app state with action A3. Once the search results are loaded, Api
will dispatch SearchResultLoaded
action to the store on the main thread.
Is there something more to the middleware than this?
Yes. The structure and logic of middleware in Redux is bit more complicated than this. Let’s do a deep dive to understand more. The middleware acts like a chain. It depends on the middleware if it wants other middleware in the chain to be invoked or not. The middleware can do following things.
- Do something (api call, db call, etc) or do not do anything.
- Update the given action or do not update it and pass it to the next in the chain and return the action that the chain returns.
- Update the given action or do not update it. Return the updated / non-updated action and ignore the chain.
Note: By updating the action, I mean creating a new instance of the same action or creating a new instance of another action. It’s better to have immutable actions.
Based on the above mentioned responsibilities, let’s update our definition and implementation of the middleware.
With Kotlin, all these interfaces can be written as higher order functions and the code becomes much more cleaner. Let’s not dwell on that right now. Api
is just some class that calls the api. We pass the store
to it because, it will call Store.dispatch(SearchResultLoaded(movies))
.
How does next work and who calls the middleware?
The implementation of Middleware is a bit confusing so let’s add some more details to our store and maybe it becomes clearer.
This code is a bit tricky and involves recursion. We create first link of chain. When creating the first link of chain, it needs the next link, so it calls the recursive method to create the next link which in turn calls the function again to create the next link. Each link consists of NextMiddleware
(weird name?) which has reference to a middleware. When we are out of middleware, we add EndOfChain
. It does not require a next and it just returns the action as is. As you can see, the order of the middleware matters here.
Redux flow with Middleware
Let’s go over the flow once again.
SearchScreen
dispatchesSearch(query="batman")
action by callingstore.dispatch(action)
- Store creates the chain of
Middleware
and calls the first link of the chain. - The first chain is a Logger. It logs the action that it receives and calls the next link of the chain with the same action.
- The next link is
SearchApiMiddleware
. It receivesSearch(query="batman")
action. It makes an API call in the background and returnsLoadingSearchResult
action. - The previous link, ie. Logger, receives
LoadingSearchResult
action as return value from the second chain. It logs this new action and returns it. - The store gets
LoadingSearchResult
action. It passes this action to the reducers. SearchScreenReducer
reducesSearchState
toSearchState.copy(loading = true)
and returns it.- No other reducer further changes the state.
- The store gets a new state and it notifies all the listener.
SearchScreen
being one of the active listeners, receives the new state and decides to show a loading spinner.- Meanwhile, the api returns a response in 200 ms. The Api.search() method having a reference to the store, dispatches
SearchResultLoaded(movies)
action. - The store creates a chain of the middleware and calls the first chain.
- None of the middlewares update the action and return it as is.
- The store gets
SearchResultLoaded
action and it calls the reducers.SearchScreenReducer
updates the SearchState toSearchState.copy(loading = false, movies=action.movies)
and returns the new state. No other reducer updates the state. - The store gets a new state and it notifies all the listener.
SearchScreen
receives the update. It hides the loading spinner and show the list of movies.
Check out this really helpful video by Shazam’s tech team which explains how a middleware works - Middleware demo. Also, here’s the article where I found the video - Android.apply{ Redux }.
I hope this was helpful and you have more understanding of Middleware
in Redux than before. In the next article, I will write about implementing the complete Redux architecture in Kotlin with higher order functions to make it look cool.
Redux architecture series
- Introduction: Redux architecture for android apps
- Middleware: Introduction and implementation
- Write your own Redux implementation in Kotlin
- Add Middleware to your Redux implementation
- Build Battleship Game with Redux - Groundwork
- Implement the Battleship gameplay with Redux
Redux architecture and Android
Learn the Redux architecture and implement the clean architecture it in your Android codebase. This series of posts explores the depth of Redux and guides you through implementing the architecture in Kotlin for your android app.